spring+hibernate實現分庫分表操作
分庫的實現:
寫一個動態的資料來源類
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());
}
}