1. 程式人生 > >spring+hibernate實現分庫分表操作

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());
}
}