首页 > 代码库 > Spring实现数据库读写分离
Spring实现数据库读写分离
http://neoremind.net/2011/06/spring%E5%AE%9E%E7%8E%B0%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB/
借助于Spring框架在2.0.1之后提供的AbstractRoutingDataSource可以实现动态的选择数据源datasource,下面先举一个最简单的例子(可以参考这个链接):
1. 首先新建 一个Catalog VO对象的DAO(见代码1),它继承了SimpleJdbcDaoSupport,JdbcDaoSupport需要注入一个DataSource,同 时也提供了操作模板JdbcTemplate。添加一个方法用于获取所有的“货物Item”。货物Iteam是一个POJO类(见代码2)。
代码1:
import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;import org.springframework.jdbc.core.simple.ParameterizedRowMapper;import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport; public class Catalog extends SimpleJdbcDaoSupport { public List<Item> getItems() { String query = "select name, price from item"; return getSimpleJdbcTemplate().query(query, new ParameterizedRowMapper<Item>() { public Item mapRow(ResultSet rs, int row) throws SQLException { String name = rs.getString(1); double price = rs.getDouble(2); return new Item(name, price); } }); }}
代码2:
public class Item { private String name; private double price; public Item(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } public String toString() { return name + " (" + price + ")"; } }
2. 配置Spring多数据源,这里配置了一个主库和一个从库,他们可以共同继承一个父的数据源。
代码3:
<bean id="parentDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" abstract="true"> <property name="driverClassName" value=http://www.mamicode.com/"com.mysql.jdbc.Driver"/> <property name="username" value=http://www.mamicode.com/"test"/></bean> <!-- 主库 --><bean id="masterDataSource" parent="parentDataSource"> <property name="url" value=http://www.mamicode.com/"jdbc:mysql://localhost:${db.port.master}/blog"/></bean> <!-- 从库 --><bean id="slaveDataSource" parent="parentDataSource"> <property name="url" value=http://www.mamicode.com/"jdbc:mysql://localhost:${db.port.slave}/blog"/></bean> <!-- 用PropertyPlaceholderConfigurer来读取properties配置,此处省略配置 --><bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value=http://www.mamicode.com/"classpath:/blog/datasource/db.properties"/></bean>
3. 新建一个 datasource继承自AbstractRoutingDataSource,并且覆盖determineCurrentLookupKey()方 法,每次用这个datasource获取数据库连接的时候都会回调这个方法获得key,根据返回的字符串key(也可以是枚举值,数字类型),动态地通过 datasource配置的id来在Spring的配置文件中找到相应的datasource来获取connection(见代码4)。那么如果每次访问 都需要根据key来决定如何选择数据源,那么这个key必须要保证线程安全,并发情况下每个线程都会去寻找本应该属于自己的key获取数据源,所以 CustomerContextHolder类中就用到了ThreadLocal来保证(见代码5)。
代码4:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class CustomerRoutingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return CustomerContextHolder.getCustomerType(); }}
代码5:
public class CustomerContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setCustomerType(String customerType) { Assert.notNull(customerType, "customerType cannot be null"); contextHolder.set(customerType); } public static String getCustomerType() { return (String) contextHolder.get(); } public static void clearCustomerType() { contextHolder.remove(); }}
在Spring中的配置如下:
代码6:
<bean id="catalog" class="blog.datasource.Catalog"> <property name="dataSource" ref="dataSource"/></bean> <bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource"> <!-- 这个targetDataSource是必须要注入的 --><property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="MASTER" value-ref="masterDataSource"/> <entry key="SLAVE" value-ref="slaveDataSource"/> </map> </property> <!-- 默认的数据源 --> <property name="defaultTargetDataSource" ref="masterDataSource"/></bean>
4. 测试用例
代码7:
AbstractDependencyInjectionSpringContextTests { private Catalog catalog; public void setCatalog(Catalog catalog) { this.catalog = catalog; } public void testDataSourceRouting() { CustomerContextHolder.setCustomerType(“MASTER”); List<Item> goldItems = catalog.getItems(); assertEquals(3, goldItems.size()); System.out.println("gold items: " + goldItems); CustomerContextHolder.setCustomerType(“SLAVE”); List<Item> silverItems = catalog.getItems(); assertEquals(2, silverItems.size()); System.out.println("silver items: " + silverItems); CustomerContextHolder.clearCustomerType(); List<Item> bronzeItems = catalog.getItems(); assertEquals(1, bronzeItems.size()); System.out.println("bronze items: " + bronzeItems); } protected String[] getConfigLocations() { return new String[] {"/blog/datasource/beans.xml"}; }}
5
您可能也喜欢:
Spring实现数据库读写分离
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。