您的位置:首页 > 编程语言 > Java开发

spring jpa 读写分离

2016-06-07 00:00 218 查看
摘要: spring jpa 读写分离

本文主要解决基于spring data jpa读写分离。
思想:在dataSource做路由,根据事务判断使用主从数据源。
背景:spring+spring data jpa(hibernate jpa)
首先是jpa配置,时间有限在原基础上该的,既有java配置也有xml配置,见谅。
先声明EntityManager
Xml代码

<!-- Jpa Entity Manager 配置 -->

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

<property name="dataSource" ref="dataSource"/>

<property name="jpaVendorAdapter">

<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

<property name="showSql" value="false" />

<property name="generateDdl" value="true" />

<property name="database" value="MYSQL" />

</bean>

</property>

<property name="packagesToScan" value="com.lee"/>

<property name="jpaProperties">

3ff0
<props>

<!-- 命名规则 My_NAME->MyName -->

<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>

</props>

</property>

</bean>

<!-- 动态dataSource -->

<bean id="dataSource" class="com.lee.spring.core.jpa.rws.RwDataSource">

<property name="targetDataSources">

<map key-type="java.lang.String">

<!-- write -->

<entry key="master" value-ref="masterDataSource"/>

<!-- read -->

<entry key="slave" value-ref="slaveDataSource"/>

</map>

</property>

<property name="defaultTargetDataSource" ref="masterDataSource"/>

</bean>

<!-- 主(写)数据源 -->

<bean id="masterDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

<property name="driverClass" value="${jdbc.master.driver}" />

<property name="jdbcUrl" value="${jdbc.master.url}" />

<property name="user" value="${jdbc.master.username}" />

<property name="password" value="${jdbc.master.password}" />

<property name="maxPoolSize" value="30" />

<property name="minPoolSize" value="10" />

<property name="initialPoolSize" value="1" />

<property name="maxIdleTime" value="0" />

<property name="acquireIncrement" value="3" />

<property name="acquireRetryAttempts" value="30" />

<property name="checkoutTimeout" value="0" />

<property name="idleConnectionTestPeriod" value="60" />

</bean>

<!-- 从(读)数据源 -->

<bean id="slaveDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

<property name="driverClass" value="${jdbc.slave.driver}" />

<property name="jdbcUrl" value="${jdbc.slave.url}" />

<property name="user" value="${jdbc.slave.username}" />

<property name="password" value="${jdbc.slave.password}" />

<property name="maxPoolSize" value="30" />

<property name="minPoolSize" value="10" />

<property name="initialPoolSize" value="1" />

<property name="maxIdleTime" value="0" />

<property name="acquireIncrement" value="3" />

<property name="acquireRetryAttempts" value="30" />

<property name="checkoutTimeout" value="0" />

<property name="idleConnectionTestPeriod" value="60" />

</bean>

用java声明的jpa设置
Java代码

import javax.annotation.Resource;

import javax.persistence.EntityManagerFactory;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.PropertySource;

import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import org.springframework.transaction.annotation.EnableTransactionManagement;

&nbs
3ff0
p;

import com.lee.spring.core.jpa.rws.MyJpaTransactionManager;

/**

* spring-jpa设置

* @author lee

*

*/

@Configuration

@PropertySource("classpath:/application.properties")

@EnableTransactionManagement

@EnableJpaRepositories(basePackages = {"com.lee.**.dao"})

public class SpringDaoConfig {

private static final Logger logger = LoggerFactory.getLogger(SpringDaoConfig.class);

@Resource(name="entityManagerFactory")

private EntityManagerFactory entityManagerFactory;

/**

* 描述 : 负责解析资源文件

* 这个类必须有,而且必须声明为static,否则不能正常解析

* @return

*/

@Bean

public static PropertySourcesPlaceholderConfigurer placehodlerConfigurer() {

logger.info("PropertySourcesPlaceholderConfigurer");

return new PropertySourcesPlaceholderConfigurer();

}

@Bean(name="entityManagerFactory")

public EntityManagerFactory entityManagerFactory() {

return entityManagerFactory;

}

@Bean(name="transactionManager")

public MyJpaTransactionManager transactionManager() {

MyJpaTransactionManager transactionManager = new MyJpaTransactionManager();

transactionManager.setEntityManagerFactory(entityManagerFactory);

return transactionManager;

}

}

由上可以看出跟平常不同的有两点

自定义动态连接池RwDataSource

自定义事务管理器MyJpaTransactionManager

其中MyJpaTransactionManager主要作用在于判断事务类别。因为我是使用注解@Transactional来声明事务,所以该类做了如下调整下载地址
Java代码

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.orm.jpa.JpaTransactionManager;

import org.springframework.transaction.TransactionDefinition;

import org.springframework.transaction.support.DefaultTransactionStatus;

@SuppressWarnings("serial")

public class MyJpaTransactionManager extends JpaTransactionManager{

private static final Logger logger = LoggerFactory.getLogger(MyJpaTransactionManager.class);

@Override

protected void doBegin(Object transaction, TransactionDefinition definition) {

if(definition.isReadOnly()){

RwDataSourceHolder.localSlave();

}else{

RwDataSourceHolder.localMaster();

}

logger.info("jpa-transaction:begin-----now dataSource is ["+RwDataSourceHolder.getDataSouce()+"]");

super.doBegin(transaction, definition);

}

@Override

protected void doCommit(DefaultTransactionStatus status) {

logger.info("jpa-transaction:commit-----now dataSource is ["+RwDataSourceHolder.getDataSouce()+"]");

super.doCommit(status);

}

}

上面涉及到definition.isReadOnly()来判断我的注解声明,依此来决定使用哪个dataSource下载
Java代码

public class RwDataSourceHolder {

public static final String MASTER = "master"; //主(写)连接池

public static final String SLAVE = "slave"; //从(读)连接池

public static final ThreadLocal<String> holder = new ThreadLocal<String>();

public static void localMaster() {

holder.set(MASTER);

}

public static void localSlave() {

holder.set(SLAVE);

}

public static String getDataSouce() {

return holder.get();

}

}

最后是RwDataSource,这个完全基于spring提供的AbstractRoutingDataSource
Java代码

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class RwDataSource extends AbstractRoutingDataSource {

@Override

protected Object determineCurrentLookupKey() {

return RwDataSourceHolder.getDataSouce();

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring jpa 读写分离