转自:
    
     Spring+Hibernate框架下MySql读写分离,主从数据库配置
    
   
    
     介绍下mysql数据库读写分离在spring,hibernate框架下的配置。
    
    
    
     1.mysql连接配置文件jdbc.properties
    
    
    
     master.*.*表示主数据库连接参数,负责增,删,改;
    
    
    
     slave.*.*表示从数据库连接参数,只负责读取;
    
    
    
    
     jdbc.properties
    
    
   
- 
      
master.jdbc.driverClassName=com.mysql.jdbc.Driver
 - 
      
master.jdbc.url=********
 - 
      
master.jdbc.username=********
 - 
      
master.jdbc.password=********
 - 
      
 - 
      
slave.jdbc.driverClassName=com.mysql.jdbc.Driver
 - 
      
slave.jdbc.url=********
 - 
      
slave.jdbc.username=********
 - 
      
slave.jdbc.password=********
 
   
    把**改成你所需的连接参数;
   
   
   
   
    2.配置AOP切面类 DataSourceAdvice.java
   
   
- 
      
import
java.lang.reflect.Method;
 - 
      
import
org.springframework.aop.AfterReturningAdvice;
 - 
      
import
org.springframework.aop.MethodBeforeAdvice;
 - 
      
import
org.springframework.aop.ThrowsAdvice;
 - 
      
 - 
      
import
com.company.datasource.DataSourceSwitcher;
 - 
      
 - 
      
public
class
DataSourceAdvice
implements
MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
 - 
      
// service方法执行之前被调用
 - 
      
public
void
before(Method method, Object[] args, Object target)
throws
Throwable {
 - 
      
System.out.println(
“切入点: ”
+ target.getClass().getName() +
“类中”
+ method.getName() +
“方法”
);
 - 
      
if
(method.getName().startsWith(
“add”
)
 - 
      
|| method.getName().startsWith(
“create”
)
 - 
      
|| method.getName().startsWith(
“save”
)
 - 
      
|| method.getName().startsWith(
“edit”
)
 - 
      
|| method.getName().startsWith(
“update”
)
 - 
      
|| method.getName().startsWith(
“delete”
)
 - 
      
|| method.getName().startsWith(
“remove”
)){
 - 
      
System.out.println(
“切换到: master”
);
 - 
      
DataSourceSwitcher.setMaster();
 - 
      
}
 - 
      
else
{
 - 
      
System.out.println(
“切换到: slave”
);
 - 
      
DataSourceSwitcher.setSlave();
 - 
      
}
 - 
      
}
 - 
      
 - 
      
// service方法执行完之后被调用
 - 
      
public
void
afterReturning(Object arg0, Method method, Object[] args, Object target)
throws
Throwable {
 - 
      
}
 - 
      
 - 
      
// 抛出Exception之后被调用
 - 
      
public
void
afterThrowing(Method method, Object[] args, Object target, Exception ex)
throws
Throwable {
 - 
      
DataSourceSwitcher.setSlave();
 - 
      
System.out.println(
“出现异常,切换到: slave”
);
 - 
      
}
 - 
      
 - 
      
}
 
   
   
    数据源选择类 DataSourceSwitcher.java
   
   
- 
      
package
com.company.datasource;
 - 
      
import
org.springframework.util.Assert;
 - 
      
 - 
      
public
class
DataSourceSwitcher {
 - 
      
@SuppressWarnings
(
“rawtypes”
)
 - 
      
private
static
final
ThreadLocal contextHolder =
new
ThreadLocal();
 - 
      
 - 
      
@SuppressWarnings
(
“unchecked”
)
 - 
      
public
static
void
setDataSource(String dataSource) {
 - 
      
Assert.notNull(dataSource,
“dataSource cannot be null”
);
 - 
      
contextHolder.set(dataSource);
 - 
      
}
 - 
      
 - 
      
public
static
void
setMaster(){
 - 
      
clearDataSource();
 - 
      
}
 - 
      
 - 
      
public
static
void
setSlave() {
 - 
      
setDataSource(
“slave”
);
 - 
      
}
 - 
      
 - 
      
public
static
String getDataSource() {
 - 
      
return
(String) contextHolder.get();
 - 
      
}
 - 
      
 - 
      
public
static
void
clearDataSource() {
 - 
      
contextHolder.remove();
 - 
      
}
 - 
      
}
 
   
   
   
    DynamicDataSource.java数据源动态切换类
   
   
- 
      
package
com.company.datasource;
 - 
      
 - 
      
import
org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
 - 
      
 - 
      
public
class
DynamicDataSource
extends
AbstractRoutingDataSource {
 - 
      
 - 
      
@Override
 - 
      
protected
Object determineCurrentLookupKey() {
 - 
      
return
DataSourceSwitcher.getDataSource();
 - 
      
}
 - 
      
 - 
      
}
 
   
   
   
    下面配置spring applicationContext.xml文件
   
   
- 
      
<?
xml
version
=
“1.0”
encoding
=
“UTF-8”
?>
 - 
      
<
beans
xmlns
=
“http://www.springframework.org/schema/beans”
 - 
      
xmlns:xsi
=
“http://www.w3.org/2001/XMLSchema-instance”
xmlns:aop
=
“http://www.springframework.org/schema/aop”
 - 
      
xmlns:tx
=
“http://www.springframework.org/schema/tx”
xmlns:context
=
“http://www.springframework.org/schema/context”
 - 
      
xsi:schemaLocation
=”
 - 
      
http://www.springframework.org/schema/beans
 - 
      
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 - 
      
http://www.springframework.org/schema/tx
 - 
      
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
 - 
      
http://www.springframework.org/schema/aop
 - 
      
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
 - 
      
http://www.springframework.org/schema/context
 - 
      
http://www.springframework.org/schema/context/spring-context-3.0.xsd”
>
 - 
      
 - 
      
<
context:annotation-config
/>
 - 
      
<!– 自动加载SERVICE DAO ACTION –>
 - 
      
<
context:component-scan
base-package
=
“cn.com.company.dao.*”
/>
 - 
      
<
context:component-scan
base-package
=
“cn.com.company.service.*”
/>
 - 
      
<
context:component-scan
base-package
=
“cn.com.company.action”
/>
 - 
      
 - 
      
<!– 加载properties配置文件 –>
 - 
      
<
bean
id
=
“propertyConfigurer”
 - 
      
class
=
“org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”
>
 - 
      
<
property
name
=
“locations”
>
 - 
      
<
list
>
 - 
      
<
value
>
classpath:jdbc.properties
</
value
>
 - 
      
</
list
>
 - 
      
</
property
>
 - 
      
</
bean
>
 - 
      
 - 
      
<
bean
id
=
“parentDataSource”
class
=
“com.mchange.v2.c3p0.ComboPooledDataSource”
>
 - 
      
//***c3p0配置
 - 
      
</
bean
>
 - 
      
<!– 主数据源–>
 - 
      
<
bean
id
=
“masterDataSource”
parent
=
“parentDataSource”
>
 - 
      
<
property
name
=
“driverClass”
value
=
“${master.jdbc.driverClassName}”
/>
 - 
      
<
property
name
=
“jdbcUrl”
value
=
“${master.jdbc.url}”
/>
 - 
      
<
property
name
=
“user”
value
=
“${master.jdbc.username}”
/>
 - 
      
<
property
name
=
“password”
value
=
“${master.jdbc.password}”
/>
 - 
      
</
bean
>
 - 
      
<!– 从数据源–>
 - 
      
<
bean
id
=
“slaveDataSource”
parent
=
“parentDataSource”
>
 - 
      
<
property
name
=
“driverClass”
value
=
“${slave.jdbc.driverClassName}”
/>
 - 
      
<
property
name
=
“jdbcUrl”
value
=
“${slave.jdbc.url}”
/>
 - 
      
<
property
name
=
“user”
value
=
“${slave.jdbc.username}”
/>
 - 
      
<
property
name
=
“password”
value
=
“${slave.jdbc.password}”
/>
 - 
      
</
bean
>
 - 
      
 - 
      
<
bean
id
=
“dataSource”
class
=
“com.company.datasource.DynamicDataSource”
>
 - 
      
<
property
name
=
“targetDataSources”
>
 - 
      
<
map
key-type
=
“java.lang.String”
>
 - 
      
<
entry
key
=
“slave”
value-ref
=
“slaveDataSource”
/>
 - 
      
</
map
>
 - 
      
</
property
>
 - 
      
<
property
name
=
“defaultTargetDataSource”
ref
=
“masterDataSource”
/>
 - 
      
</
bean
>
 - 
      
 - 
      
<!– 配置sessionFactory –>
 - 
      
<
bean
id
=
“sessionFactory”
 - 
      
class
=
“org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”
>
 - 
      
<
property
name
=
“dataSource”
ref
=
“dataSource”
>
</
property
>
 - 
      
<
property
name
=
“packagesToScan”
value
=
“cn.com.company.entity”
/>
 - 
      
<
property
name
=
“hibernateProperties”
>
 - 
      
<
props
>
 - 
      
 - 
      
<
prop
>
//***hibernate一些参数这里不写了
</
prop
>
 - 
      
</
props
>
 - 
      
</
property
>
 - 
      
</
bean
>
 - 
      
 - 
      
<!– 切换数据源 –>
 - 
      
<
bean
id
=
“dataSourceAdvice”
class
=
“com.company.aop.DataSourceAdvice”
/>
 - 
      
<
aop:config
>
 - 
      
<
aop:advisor
 - 
      
pointcut
=
“execution(* cn.com.company.service..*Service.*(..))”
 - 
      
advice-ref
=
“dataSourceAdvice”
/>
 - 
      
</
aop:config
>
 - 
      
 - 
      
<!– 配置事务管理器 –>
 - 
      
<
bean
id
=
“transactionManager”
 - 
      
class
=
“org.springframework.orm.hibernate3.HibernateTransactionManager”
>
 - 
      
<
property
name
=
“sessionFactory”
>
 - 
      
<
ref
bean
=
“sessionFactory”
/>
 - 
      
</
property
>
 - 
      
</
bean
>
 - 
      
<!–配置事务的传播特性 –>
 - 
      
<
tx:advice
id
=
“txAdvice”
transaction-manager
=
“transactionManager”
>
 - 
      
<
tx:attributes
>
 - 
      
<!– 对增、删、改方法进行事务支持 –>
 - 
      
<
tx:method
name
=
“add*”
propagation
=
“REQUIRED”
/>
 - 
      
<
tx:method
name
=
“create*”
propagation
=
“REQUIRED”
/>
 - 
      
<
tx:method
name
=
“save*”
propagation
=
“REQUIRED”
/>
 - 
      
<
tx:method
name
=
“edit*”
propagation
=
“REQUIRED”
/>
 - 
      
<
tx:method
name
=
“update*”
propagation
=
“REQUIRED”
/>
 - 
      
<
tx:method
name
=
“delete*”
propagation
=
“REQUIRED”
/>
 - 
      
<
tx:method
name
=
“remove*”
propagation
=
“REQUIRED”
/>
 - 
      
<!– 对查找方法进行只读事务 –>
 - 
      
<
tx:method
name
=
“loadByUsername*”
propagation
=
“SUPPORTS”
read-only
=
“true”
/>
 - 
      
<!– 对其它方法进行只读事务 –>
 - 
      
<
tx:method
name
=
“*”
propagation
=
“SUPPORTS”
read-only
=
“true”
/>
 - 
      
</
tx:attributes
>
 - 
      
</
tx:advice
>
 - 
      
<!–那些类的哪些方法参与事务 –>
 - 
      
<
aop:config
>
 - 
      
<
aop:advisor
 - 
      
pointcut
=
“execution(* cn.com.company.service..*Service.*(..))”
 - 
      
advice-ref
=
“txAdvice”
/>
 - 
      
<
aop:advisor
 - 
      
pointcut
=
“execution(* cn.com.company.service..*ServiceImpl.*(..))”
 - 
      
advice-ref
=
“txAdvice”
/>
 - 
      
</
aop:config
>
 - 
      
 - 
      
 - 
      
</
beans
>
 
   
   
   
    !注 applicationContenxt.xml中
    
    <!– 切换数据源 –>
    
    <bean id=”dataSourceAdvice” class=”com.company.aop.DataSourceAdvice” />
    
    <aop:config>
    
    <aop:advisor
    
    pointcut=”execution(* cn.com.company.service..*Service.*(..))”
    
    advice-ref=”dataSourceAdvice” />
    
    </aop:config>
    
    一定要配置在事务AOP之上