`
kkdo
  • 浏览: 3241 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

spring的事务管理(但数据源多数据源)

阅读更多
一.单一数据源的事务管理

事务的管理有几种方式, 使用注解, 声明式配置等等.

首先,看一下单一数据源的事务配置:

<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation=" 
http://www.springframework.org/schema/beans       
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/context     
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx         
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<!-- 扫描注解Bean -->
<context:component-scan base-package="com.tx">
</context:component-scan>

<tx:annotation-driven proxy-target-class="true"
transaction-manager="txManager" />

<context:property-placeholder location="classpath:jdbc.properties" />

<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>



<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="txManager" />
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="clear*">PROPAGATION_REQUIRED</prop>
<prop key="restore*">PROPAGATION_REQUIRED</prop>
<prop key="replace*">PROPAGATION_REQUIRED</prop>
<prop key="process*">PROPAGATION_REQUIRED</prop>
<prop key="execute*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 设置代理类 -->
<bean id="bdf.transaction.beanNameAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="proxyTargetClass" value="true"></property>
<property name="beanNames" value="*PR,*BO,*Service,*Dao" />
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<!-- 设置事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
基本属性 url、user、password
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
配置初始化大小、最小、最大
<property name="initialSize" value="1" />
<property name="minIdle" value="1" />
<property name="maxActive" value="20" />
配置获取连接等待超时的时间
<property name="maxWait" value="60000" />
配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
<property name="timeBetweenEvictionRunsMillis" value="60000" />
配置一个连接在池中最小生存的时间,单位是毫秒
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT * from user" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
打开PSCache,并且指定每个连接上PSCache的大小
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="20" />
配置监控统计拦截的filters
<property name="filters" value="stat" />
</bean> -->

<!-- 配置数据源,c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
</beans> 
其中transactionInterceptor中配置的拦截方法就是需要事务管理的, 满足命名条件的方法都会被事务管理所拦截.

测试:



/* Dao代码 */
public class JdbcTestDao {

@Resource(name="jdbctemplate")
JdbcTemplate jdbcTemplate;

/**
* 在配置文件中使用了声明式的事务管理,<prop key="execute*">PROPAGATION_REQUIRED</prop>
* 所以这个事务是会被拦截的事务
*/
public void execute(){
jdbcTemplate.update("UPDATE user set username = 'fff1' where id=4");
jdbcTemplate.update("UPDATE user1 set username = 'eee1' where id=4");
int i = 1/0;
}

/**
* 这个虽然不是在配置文件中需要被拦截的事务,但是有注解声明
* 所以这个事务是会被拦截的事务
*/
@Transactional
public void notExtcuteWithTx(){
jdbcTemplate.update("UPDATE user set username = 'ggg' where id=4");
jdbcTemplate.update("UPDATE user1 set username = 'hhh' where id=4");
int i = 1/0;
}

/**
* 不会被拦截的事务
*/
public void notExtcute(){
jdbcTemplate.update("UPDATE user set username = 'iii' where id=4");
jdbcTemplate.update("UPDATE user1 set username = 'jjjj' where id=4");
int i = 1/0;
}
}
/* jUnit代码 */
public class JdbcTestDaoTest {
ApplicationContext context;

@Before
public void before() {
context = new ClassPathXmlApplicationContext("spring-jdbc.xml");
}

@Test
public void execute() {
JdbcTestDao dao = context.getBean(JdbcTestDao.class);
dao.execute();
}
@Test
public void notExtcuteWithTx() {
JdbcTestDao dao = context.getBean(JdbcTestDao.class);
dao.notExtcuteWithTx();
}
@Test
public void notExtcute() {
JdbcTestDao dao = context.getBean(JdbcTestDao.class);
dao.notExtcute();
}
}
分别单元测试三个方法, 可以得到正确的结果, 当抛出异常的时候, 事务都会回滚.





二.多数据源的事务管理

    在spring中, 提供了很多事务管理的接口, DataSourceTransactionManager, JpaTransactionManager,  JtaTransactionManager等等. 其中JtaTransactionManager是专门用来管理多数据源, 提供了对分布式事务的支持.

<!-- JTA分布式事务配置 -->
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation=" 
http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/context      http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<!-- 扫描注解Bean -->
<context:component-scan base-package="com.tx">
</context:component-scan>
<tx:annotation-driven proxy-target-class="true"
transaction-manager="transactionManager" />
<bean id="jdbctemplate1" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource1" />
</bean>

<bean id="jdbctemplate2" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource2" />
</bean>

<bean id="dataSource1" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="mysql1" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="url">jdbc:mysql://localhost:3306/chatroom?useUnicode=true&amp;characterEncoding=utf8
</prop>
<prop key="user">root</prop>
<prop key="password">123456</prop>
<!-- <prop key="initialSize">1</prop> <prop key="minIdle">1</prop> <prop
key="maxActive">20</prop> -->
</props>
</property>
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="borrowConnectionTimeout" value="30" />
<property name="testQuery" value="select 1" />
<property name="maintenanceInterval" value="60" />
</bean>

<bean id="dataSource2" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="mysql2" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="url">jdbc:mysql://localhost:3306/cms?useUnicode=true&amp;characterEncoding=utf8
</prop>
<prop key="user">root</prop>
<prop key="password">123456</prop>
<!-- <prop key="initialSize">1</prop> <prop key="minIdle">1</prop> <prop
key="maxActive">20</prop> -->
</props>
</property>
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="borrowConnectionTimeout" value="30" />
<property name="testQuery" value="select 1" />
<property name="maintenanceInterval" value="60" />
</bean>

<!-- 设置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown" value="true" />
</bean>
</property>
<property name="userTransaction">
<bean class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
</property>
</bean>


<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="clear*">PROPAGATION_REQUIRED</prop>
<prop key="restore*">PROPAGATION_REQUIRED</prop>
<prop key="replace*">PROPAGATION_REQUIRED</prop>
<prop key="process*">PROPAGATION_REQUIRED</prop>
<prop key="execute*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 设置代理类 -->
<bean id="transactionBeanNameAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="proxyTargetClass" value="true"></property>
<property name="beanNames" value="*PR,*BO,*Service,*Dao" />
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
</beans> 
    这里,使用的都是mysql, 只是数据库不同, 也可以使用多种数据库,可替换为oracle等.

    测试:

   

/* Dao代码 */
@Component
public class JtaTestDao implements ApplicationContextAware ,InitializingBean{
private ApplicationContext context;

public void execute() {
JdbcTemplate chatroom = context.getBean("jdbctemplate1",
JdbcTemplate.class);
JdbcTemplate cms = context.getBean("jdbctemplate2",
JdbcTemplate.class);
chatroom.update("UPDATE user set username = 'lzxfgw' where id=4");
cms.update("INSERT INTO c_user (id, login_name, password) values (100, 'fgw', '123')");

}

//@PostConstruct
    //实现ApplicationContextAware接口, 可以在初始化的时候注入applicationContext
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}

@Override
public void afterPropertiesSet() throws Exception {
}
}
/* jUnit代码 */
public class JtaTestDaoTest {
ApplicationContext context;

@Test
public void test() {
JtaTestDao t = context.getBean(JtaTestDao.class);
t.execute();
}

@Before
public void before() {
context = new ClassPathXmlApplicationContext("spring-jta.xml");
}
}
    运行jUnit第一次是没有问题的, 修改一下dao代码中的username再次运行,会抛出主键重复的异常, 可以看到数据库中的第一条update语句的username也没有改变, 说明事务在抛出异常之后正常回滚了.
分享到:
评论

相关推荐

    Spring Boot多数据源(支持Spring声明式事务切换和回滚).pdf

    在本文中,我们将深入探讨如何实现动态数据源切换,支持Spring声明式事务管理,并讨论多数据源回滚策略。以下是对这些知识点的详细说明: 1. **动态数据源切换**: - 通过AspectJ实现数据源的动态切换,可以设置在...

    Spring多数据源分布式事务管理

    总的来说,Spring多数据源分布式事务管理是一项复杂的任务,涉及到Spring的AOP、数据源路由、事务管理等多个方面。通过Atomikos这样的JTA实现,我们可以有效地解决分布式环境下的事务一致性问题。同时,结合Druid和...

    spring boot 2多数据源,里面有hibernate和mybatis的多数据源代码

    2. **配置事务管理器**:由于存在多个数据源,我们需要为每个数据源创建一个PlatformTransactionManager。Spring Boot 2支持自动配置,只需添加对应的`@EnableTransactionManagement`和`@Transactional`注解。 3. *...

    springboot实现多数据源而且加上事务不会使aop切换数据源失效

    本示例主要讲解如何使用Spring Boot结合MyBatis实现多数据源切换,并确保AOP事务管理仍然有效。 首先,我们需要配置多数据源。在Spring Boot中,可以使用`DataSource`接口的实现类,如`HikariCP`或`Druid`,创建两...

    spring整合mybatis多数据源

    5. **事务管理**:在多数据源环境下,事务管理也需要特别注意。Spring的PlatformTransactionManager应配置为DataSourceTransactionManager,并且需要确保它知道如何处理多个数据源。在事务开始时,事务管理器会根据...

    spring+jotm 多数据源事务管理(二)hibernate

    在Spring框架中,多数据源事务管理是一项关键任务,特别是在大型企业级应用中,往往需要同时操作多个数据库。本篇文章将聚焦于如何结合Spring和JOTM(Java Open Transaction Manager)来实现多数据源的事务管理,...

    spring+druid+AtomikosDataSource实现多数据源切换及分布式事务控制

    在现代企业级应用开发中,多数据源切换和分布式事务管理是常见的需求,尤其是在大型分布式系统中。Spring框架因其强大的依赖注入和AOP(面向切面编程)特性,成为Java领域首选的轻量级框架。Druid是一个优秀的数据库...

    Springboot 动态多数据源 jta分布式事务

    总之,Spring Boot的多数据源和JTA分布式事务功能为企业级应用提供了强大的支撑,让开发者可以灵活地处理复杂的数据操作和事务管理。如果你是初学者,通过在线教程和提供的`demo`项目,相信你能够快速掌握这一技能。

    spring boot多数据源配置

    在Spring Boot应用中,多数据源配置是一项关键的技术,它允许我们同时管理多个数据库,比如主库和从库,或者不同类型的数据库。本教程将详细阐述如何在Spring Boot项目中实现这一功能,从数据源配置、实体管理到...

    Springcloud 多数库 多数据源整合,查询动态切换数据库

    3. **Spring Cloud Config Server**:为了更好地管理和维护多数据源的配置,我们可以结合Spring Cloud Config Server,将配置集中存储并管理。这样,当需要更新数据库配置时,只需更改Config Server上的配置,服务端...

    Spring动态切换多数据源Demo

    总的来说,"Spring动态切换多数据源Demo"是一个实战教程,旨在教你如何在Spring应用程序中实现数据源的动态切换,以及如何处理相关的配置和事务管理。通过学习这个Demo,你可以掌握在Spring环境中处理多数据库连接的...

    Spring配置多个数据源

    Spring框架提供了一种灵活的方式来配置和管理多个数据源,使得这种需求变得简单易行。本文将详细介绍如何在Spring应用中配置多个数据源。 首先,我们来理解数据源(DataSource)的概念。数据源是Java中用于存储...

    spring3+springmvc+jpa+hibernate多数据源

    多数据源的配置通常涉及到数据源的切换策略、事务管理以及如何根据业务逻辑选择合适的数据源。 在实现这个多数据源的集成时,开发者可能需要做以下工作: 1. **配置不同数据源**:在Spring配置文件中,为每个数据...

    Spring+Hibernate多数据源

    本示例将探讨如何在Spring和Hibernate环境中实现多数据源的配置与管理。 首先,我们来看标题"Spring+Hibernate多数据源",这意味着我们要在一个项目中同时配置和使用两个数据源。通常,这涉及到创建两个不同的...

    spring,mybatis 对数据源配置与管理

    在企业级应用开发中,经常需要访问和操作多个数据库,这种需求促使了多数据源配置与管理在Spring框架和MyBatis持久层框架中的重要性。下面对这个主题的知识点进行详细说明。 1. **多数据源场景介绍** 在处理多数据...

    SpringBoot-SpringData-多数据源

    Spring Boot 和 Spring Data 联合使用,使得多数据源的配置和管理变得简单易行。通过合理的配置和编程,可以有效地管理和切换不同数据源,满足复杂的企业级应用需求。同时,多数据源策略还有助于数据库的扩展和维护...

    SpringBoot+Atomikos+动态多数据源+事务+2种切换数据源的方式

    3. **事务管理**:SpringBoot默认使用LocalContainerEntityManagerFactoryBean处理JPA事务,但在多数据源环境中,需要改为使用Atomikos的`JtaPlatformTransactionManager`。此外,确保开启@...

    spring数据源配置

    Spring框架作为一种流行的轻量级Java应用开发框架,提供了强大的数据库访问支持,其中包括对数据源的配置管理。数据源(DataSource)在Spring中的配置对于实现持久层操作至关重要。 #### 二、Spring中的数据源配置...

    springboot多数据源即分布式事务解决方案

    SpringBoot作为一款轻量级的框架,提供了便捷的多数据源配置和分布式事务管理方案,使得开发者能够高效地管理和操作不同的数据库。本文将详细探讨SpringBoot如何实现多数据源以及分布式事务。 首先,我们要理解什么...

    spring多数据源

    1. **DataSourceTransactionManager**:Spring的事务管理器,负责处理数据源的事务。当配置了多个数据源时,我们需要为每个数据源创建一个DataSourceTransactionManager实例,并在Spring配置文件中指定对应的Data ...

Global site tag (gtag.js) - Google Analytics