之前的项目使用的是SpringMVC+Spring+Hibernate的框架,在dao层上的配置是这样的
<!-- 读取用的数据库session工厂 -->
<bean id="readSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="readDataSource" />
<property name="packagesToScan">
<list>
<value>com.xxx.xxxx.xxxx.persistence.entities</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean><!-- 读取的数据库映射 -->
<bean id="readDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${read.jdbc.driverClassName}" />
<property name="url" value="${read.jdbc.url}" />
<property name="username" value="${read.jdbc.user}" />
<property name="password" value="${read.jdbc.pass}" />
</bean><!-- 写出用的数据库session工厂 -->
<bean id="writeSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="writeDataSource" />
<property name="packagesToScan">
<list>
<value>com.xxx.xxxx.xxxx.persistence.entities</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean><!-- 写出的数据库映射 -->
<bean id="writeDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${write.jdbc.driverClassName}" />
<property name="url" value="${write.jdbc.url}" />
<property name="username" value="${write.jdbc.user}" />
<property name="password" value="${write.jdbc.pass}" />
</bean><!-- 配置事务管理器 -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="writeSessionFactory" />
</bean>
<!-- 配置切入点 -->
<aop:config>
<aop:pointcut id="allMethods"
expression="execution(* com.xxx.xxxx.xxxx.service.impl.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="allMethods" />
</aop:config>
<!-- 配置事务方法 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="list*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
以上的配置,都是在xml文件中配置的,那么转到springboot上,需要在config类中配置
第一步:配置数据源
看源码,springboot的DataSourceBuilder,可知DataSource类型有以下几种,
private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {
"org.apache.tomcat.jdbc.pool.DataSource",
"com.zaxxer.hikari.HikariDataSource",
"org.apache.commons.dbcp.BasicDataSource", // deprecated
"org.apache.commons.dbcp2.BasicDataSource" };
在 DataSourceConfiguration.tomcat.class类中,可以看到,默认使用的是org.apache.tomcat.jdbc.pool.DataSource
/**
* Tomcat Pool DataSource configuration.
*/
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
static class Tomcat extends DataSourceConfiguration {................
}
myDataSourceConfig.class类
@Configuration
public class MyDataSourceConfig {@Bean(name="readDataSource")
@Qualifier("readDataSource")
@ConfigurationProperties(prefix="read.jdbc")
public DataSource readDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name="writeDataSource")
@Qualifier("writeDataSource")
@Primary
@ConfigurationProperties(prefix="write.jdbc")
public DataSource writeDataSource() {
return DataSourceBuilder.create().build();
}
application.properties文件中,数据库的链接配置(因为我本地的mysql是8.0,所以配置与5.7的有所不同)
#数据库session工厂配置
read.jdbc.driverClassName=com.mysql.cj.jdbc.Driver
read.jdbc.url=jdbc:mysql://172.0.0.1:3306/springbootdemo?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
read.jdbc.username=root
read.jdbc.password=rootwrite.jdbc.driverClassName=com.mysql.cj.jdbc.Driver
write.jdbc.url=jdbc:mysql://172.0.0.1:3306/springbootdemo?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
write.jdbc.username=root
write.jdbc.password=rootspring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
//current_session_context_class该属性配置,是为了加载Hibernate的sessionFactory,而不是使用默认的
因为springboot默认加载的是 DataSourceAutoConfiguration.class,即在application文件上设置的两个数据源没办法被其识别,我需要自己手动加入,并去掉默认加载exclude = { DataSourceAutoConfiguration.class },同时在application.properties文件上加入current_session_context_class属性
第二步,配置sessionFactory
@Configuration
@Import(MyDataSourceConfig.class)
public class MySessionFactory {@Autowired
@Qualifier("readDataSource")
private DataSource readDataSource;@Autowired
@Qualifier("writeDataSource")
private DataSource writeDataSource;@Value(value = "${spring.jpa.show-sql}")
private String showSql;
@Value(value = "${spring.jpa.properties.hibernate.dialect}")
private String dialect;
@Value(value = "${spring.jpa.hibernate.ddl-auto}")
private String ddlAuto;@Bean(name = "readSessionFactory")
public LocalContainerEntityManagerFactoryBean readSessionFactory(EntityManagerFactoryBuilder builder) {return builder.dataSource(readDataSource).properties(getHibernateProperties(readDataSource))
.packages("com.xingfu.springboot.persistence.entity").build();
}
@Bean
public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf){
return hemf.getSessionFactory(); //必须添加,否则不会加载你所设置的HibernateSessionFactory
}
@Bean(name = "writeSessionFactory")
@Primary //配置为默认sessionFactory,不设置,两个sessionFactory就无法查找是那个
public LocalContainerEntityManagerFactoryBean writeSessionFactory(EntityManagerFactoryBuilder builder) {return builder.dataSource(writeDataSource).properties(getHibernateProperties(writeDataSource))
.packages("com.xingfu.springboot.persistence.entity").build();
}@Autowired(required = false)
private JpaProperties jpaProperties;private Map<String, String> getHibernateProperties(DataSource dataSource) {
Map<String, String> hibernateMap = jpaProperties.getHibernateProperties(dataSource);
hibernateMap.put("hibernate.show_sql", showSql);
hibernateMap.put("hibernate.dialect", dialect);
hibernateMap.put("hibernate.hbm2ddl.auto", ddlAuto);
return hibernateMap;
}
}
application.properties文件的配置
spring.jpa.database = MYSQL
spring.jpa.show-sql = false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto = update
第三步,配置事物和切面
@Configuration
@Aspect
@Import(value= {MySessionFactory.class})
public class MyHibernateConfig{@Autowired
@Qualifier("writeSessionFactory")
private LocalContainerEntityManagerFactoryBean writeSessionFactory;
/** 事物切入点 */
private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.xingfu.springboot.service.impl.*.*(..))";
@Bean(name = "txManager")
public PlatformTransactionManager txManager() {
return new JpaTransactionManager(writeSessionFactory.getObject());
}@Bean
public TransactionInterceptor transctionInterceptor() {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
readOnlyTx.setReadOnly(true);
readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("*", requiredTx);
txMap.put("get*", readOnlyTx);
txMap.put("find*", readOnlyTx);
txMap.put("list*", readOnlyTx);
source.setNameMap(txMap);
TransactionInterceptor txAdvice = new TransactionInterceptor(txManager(), source);
return txAdvice;
}@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut,transctionInterceptor());
}}
配置完成.
参考资料:
https://www.jianshu.com/p/1db9e7667fa7
https://blog.csdn.net/neosmith/article/details/61202084
https://segmentfault.com/q/1010000009512587
http://blog.didispace.com/springboottransactional/
https://blog.csdn.net/nextyu/article/details/78669997