分库的实现:
写一个动态的数据源类
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
// TODO Auto-generated method stub
return DbContextHolder.getDbType();
}
}
public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal();
public static void setDbType(String dbType) {
contextHolder.set(dbType);
}
public static String getDbType() {
String str = (String) contextHolder.get();
if (StringUtils.isEmpty(str))
str = "1";
return str;
}
public static void clearDbType() {
contextHolder.remove();
}
}
这里主要用到一个线程本地化,实现同一个线程中的数据传递,我的理解是:请求过来,controller->service->dao->datasource这是在同一个线程 里,而要想从controller传一个数据到datasource,所有可以使用threadLocal
配制如下:
<!-- 多数据源配只 -->
<bean id="dataSource" class="com.lin.datasource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="1" value-ref="dataSource1"></entry>
<entry key="2" value-ref="dataSource2"></entry>
</map>
</property>
<!-- 莫认的 -->
<property name="defaultTargetDataSource" ref="dataSource1"></property>
</bean>
<!-- 数据源 -->
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverclass}" />
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxPoolSize" value="${c3p0.pool.size.max}" />
<property name="minPoolSize" value="${c3p0.pool.size.min}" />
<property name="initialPoolSize" value="${c3p0.pool.size.ini}" />
<property name="acquireIncrement" value="${c3p0.pool.size.increment}" />
</bean>
<bean id="dataSource2" parent="dataSource1">
<property name="jdbcUrl" value="${jdbc.url2}"></property>
</bean>
<!-- 本地会话工程bean,是spring整合hibernate的核心 入口 -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
<!-- 映射文件的目录 -->
<property name="mappingDirectoryLocations">
<list>
<value>classpath:com/lin/domain</value>
</list>
</property>
</bean>
测试:
@Autowired
private StudentService studentService;
@RequestMapping("/add")
public @ResponseBody String add(String type){
if(type==null)type="default";
DbContextHolder.setDbType(type);
Student student=new Student();
student.setAge(10);
student.setName("fdf"+type);
studentService.save(student);
return type;
}
传一个type,定向到哪一个数据库,就可以了
分表的实现:
主要是使用了hibernate的拦截器
public class QueryResInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = 8307241774485402107L;
private String viewName;
private String fix;
public QueryResInterceptor(String viewName,String fix) {// 写个构造方法,根据参数来确定是增删改查那张表
this.viewName = viewName;
this.fix=fix;
}
@Override
public String onPrepareStatement(String sql) {
//重写该方法,hibernate是封装了jdbc的,但他底层还是通过sql来操作的。
if(viewName.equals("order")){//只有order表才使用多表
sql = sql.replace(viewName,viewName+"_"+fix);
System.out.println("sql_______"+sql);
}
return sql;
}
}
通过拦截器改变sq语句的表名
dao层的实现如下:
@Override
public void saveOrder(Order order,String fix) {
//加一个难截器,实现多表插入
QueryResInterceptor interceptor = new QueryResInterceptor("order",fix);
Session session = this.getHibernateTemplate().getSessionFactory()
.openSession(interceptor);
session.save(order);
}
@Override
public List<Order> selectList(String fix) {
QueryResInterceptor interceptor=new QueryResInterceptor("order", fix);
Session session=this.getHibernateTemplate().getSessionFactory().openSession(interceptor);
List<Order> orders=session
.createQuery("select o from "+Order.class.getSimpleName()+" o")
.list();
return orders;
}
就这样就可以了
测试如下:
@Test
public void add(){
OrderService orderService=(OrderService)context.getBean("orderServiceImpl");
Order order=new Order();
order.setContent("jfkd");
String fix="4";//多表中的后缀
orderService.save(order,fix);
}
@Test
public void select(){
OrderService orderService=(OrderService)context.getBean("orderServiceImpl");
List<Order>orders=orderService.selectList("2");
for (Order order : orders) {
System.out.println(order.getId());
}
}