- 浏览: 690823 次
- 性别:
- 来自: 成都
-
文章分类
- 全部博客 (129)
- Java (13)
- Android (9)
- J2ee (3)
- Swt/jface (0)
- SSH (9)
- C/C++ (1)
- php (1)
- Algorithm (2)
- Apache/Nginx (12)
- Bea/Tomcat (2)
- Oracle/Mysql (10)
- Sql/derby (17)
- Unix/Linux (11)
- Hadoop (1)
- Hbase (15)
- Redis (2)
- Lucene/Solr (0)
- Httpclient (1)
- Groovy (2)
- SoftwareEng (2)
- HTML/JS/CSS (3)
- Flex (1)
- log4j (1)
- Protocol (3)
- windows (0)
- Tools (1)
- docker (1)
- k8s (1)
- Business (3)
- Others (3)
最新评论
6.3 Spring的事务
Spring的事务管理不需与任何特定的事务API耦合。对不同的持久层访问技术,编程式事务提供一致
的事务编程风格,通过模板化的操作一致性地管理事务。声明式事务基于Spring AOP实现,却并不需
要程序开发者成为AOP专家,亦可轻易使用Spring的声明式事务管理。
6.3.1 Spring支持的事务策略
Spring事务策略是通过PlatformTransactionManager接口体现的,该接口是Spring事务策略的核心。
该接口的源代码如下:
public interface PlatformTransactionManager { //平台无关的获得事务的方法 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; //平台无关的事务提交方法 void commit(TransactionStatus status) throws TransactionException; //平台无关的事务回滚方法 void rollback(TransactionStatus status) throws TransactionException; }
PlatformTransactionManager是一个与任何事务策略分离的接口,随着底层不同事务策略切换,应用
必须采用不同的实现类。PlatformTransactionManager接口没有与任何事务资源捆绑在一起,它可以
适应于任何的事务策略,结合Spring的IoC容器,可以向PlatformTransactionManager注入相关的平
台特性。
PlatformTransactionManager接口有许多不同的实现类,应用程序面向与平台无关的接口编程,对不
同平台的底层支持,由PlatformTransactionManager接口的实现类完成。从而,应用程序无须与具体
的事务API耦合。因此,使用PlatformTransactionManager接口,可将代码从具体的事务API中解耦出
来。
即使使用特定容器管理的JTA,代码依然无须执行JNDI查找,无须与特定的JTA资源耦合在一起。通过
配置文件,JTA资源传给PlatformTransactionManager的实现类。因此,程序的代码可在JTA事务管理
和非JTA事务管理之间轻松切换。
在PlatformTransactionManager接口内,包含一个getTransaction(TransactionDefinition
definition)方法,该方法根据一个TransactionDefinition参数,返回一个TransactionStatus对象
。TransactionStatus对象表示一个事务。TransactionStatus被关联在当前执行的线程。
getTransaction(TransactionDefinition definition)返回的TransactionStatus对象,可能是一
个新的事务,也可能是一个已经存在的事务对象。如果当前执行的线程已经处于事务管理下,返回当
前线程的事务对象,否则,返回当前线程的调用堆栈已有的事务对象。
TransactionDefinition接口定义了一个事务规则,该接口必须指定如下几个属性值:
● 事务隔离,当前事务和其他事务的隔离程度。例如,这个事务能否看到其他事务未提交的数据
等。
● 事务传播,通常,在事务中执行的代码都会在当前事务中运行。但是,如果一个事务上下文已
经存在,有几个选项可指定该事务性方法的执行行为。例如,大多数情况下,简单地在现有的事务上
下文中运行;或者挂起现有事务,创建一个新的事务。Spring提供EJB CMT(Contain Manager
Transaction,容器管理事务)中所有的事务传播选项。
● 事务超时,事务在超时前能运行多久。事务的最长持续时间。如果事务一直没有被提交或回滚
,将在超出该时间后,系统自动回滚事务。
● 只读状态,只读事务不修改任何数据。在某些情况下(例如使用Hibernate时),只读事务是非
常有用的优化。
TransactionStatus代表事务本身,它提供了简单的控制事务执行和查询事务状态的方法。这些方法
在所有的事务API中都是相同的。TransactionStatus接口的源代码如下:
public interface TransactionStatus { //判断事务是否是新建的事务 boolean isNewTransaction(); //设置事务回滚 void setRollbackOnly(); //查询事务是否已有回滚标志 boolean isRollbackOnly(); }
Spring的事务管理由PlatformTransactionManager的不同实现类完成。在Spring上下文中配置
PlatformTransactionManager Bean时,必须针对不同环境提供不同的实现类。
下面提供不同的持久层访问环境,及其对应的PlatformTransactionManager实现类的 配置。
JDBC数据源的局部事务策略:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Spring配置文件的根元素,以及Spring配置文件的Schema信息 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 定义数据源Bean,使用C3P0数据源实现 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy- method="close"> <!-- 指定连接数据库的驱动 --> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <!-- 指定连接数据库的URL --> <property name="jdbcUrl" value="jdbc:mysql://localhost/j2ee"/> <!-- 指定连接数据库的用户名 --> <property name="user" value="root"/> <!-- 指定连接数据库的密码 --> <property name="password" value="32147"/> <!-- 指定连接数据库连接池的最大连接数 --> <property name="maxPoolSize" value="40"/> <!-- 指定连接数据库连接池的最小连接数 --> <property name="minPoolSize" value="1"/> <!-- 指定连接数据库连接池的初始化连接数 --> <property name="initialPoolSize" value="1"/> <!-- 指定连接数据库连接池的连接最大空闲时间 --> <property name="maxIdleTime" value="20"/> </bean> <!-- 配置JDBC数据源的局部事务管理器 --> <!-- 使用DataSourceTransactionManager 类,该类实现PlatformTransactionManager接口 --> <!-- 针对采用数据源连接的特定实现 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource. DataSourceTransactionManager"> <!-- DataSourceTransactionManager bean需要依赖注入一个DataSource bean的引用 --> <property name="dataSource" ref="dataSource"/> </bean> </beans>
对于容器管理JTA数据源,全局事务策略的配置文件如下:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Spring配置文件的根元素,以及Spring配置文件的Schema信息 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 配置JNDI数据源Bean --> <bean id="dataSource" class="org.springframework.jndi. JndiObjectFactoryBean"> <!-- 容器管理数据源的JNDI --> <property name="jndiName" value="jdbc/jpetstore"/> </bean> <!-- 使用JtaTransactionManager类,该类实现PlatformTransactionManager接 口 --> <!-- 针对采用全局事务管理的特定实现 --> <!-- JtaTransactionManager不需要知道数据源,或任何其他特定资源 --> <!-- 因为它使用容器的全局事务管理 --> <bean id="transactionManager" class="org.springframework.transaction.jta. JtaTransactionManager" /> </beans>
对于采用Hibernate持久层访问策略时,局部事务策略的配置文件如下:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Spring配置文件的根元素,以及Spring配置文件的Schema信息 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 定义数据源Bean,使用C3P0数据源实现 --> <bean id="dataSource" class="com.mchange.v2.c3p0. ComboPooledDataSource" destroy-method="close"> <!-- 指定连接数据库的驱动 --> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <!-- 指定连接数据库的URL --> <property name="jdbcUrl" value="jdbc:mysql://localhost/j2ee"/> <!-- 指定连接数据库的用户名 --> <property name="user" value="root"/> <!-- 指定连接数据库的密码 --> <property name="password" value="32147"/> <!-- 指定连接数据库连接池的最大连接数 --> <property name="maxPoolSize" value="40"/> <!-- 指定连接数据库连接池的最小连接数 --> <property name="minPoolSize" value="1"/> <!-- 指定连接数据库连接池的初始化连接数 --> <property name="initialPoolSize" value="1"/> <!-- 指定连接数据库连接池的连接最大空闲时间 --> <property name="maxIdleTime" value="20"/> </bean> <!-- 定义Hibernate的SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3. LocalSessionFactoryBean"> <!-- 依赖注入SessionFactory所需的数据源,正是上文定义的dataSource --> <property name="dataSource" ref="dataSource"/> <!-- mappingResources属性用来列出全部映射文件 --> <property name="mappingResources"> <list> <!-- 以下用来列出所有的PO映射文件 --> <value>lee/MyTest.hbm.xml</value> </list> </property> <!-- 定义Hibernate的SessionFactory的属性 --> <property name="hibernateProperties"> <props> <!-- 指定Hibernate的连接方言 --> <prop key="hibernate.dialect">org.hibernate.dialect. MySQLDialect</prop> <!-- 是否根据Hibernate映射创建数据表时,选择create、update、 create-drop --> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 配置Hibernate的局部事务管理器 --> <!-- 使用HibernateTransactionManager类,该类是PlatformTransactionManager 接口,针对采用Hibernate持久化连接的特定实现 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3. HibernateTransactionManager"> <!-- HibernateTransactionManager Bean需要依赖注入一个 SessionFactorybean的引用 --> <property name="sessionFactory" ref="sessionFactory"/> </bean> </beans>
对于采用Hibernate持久层访问策略时,全局事务策略的配置文件如下:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Spring配置文件的根元素,以及Spring配置文件的Schema信息 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 配置JNDI数据源Bean --> <bean id="dataSource" class="org.springframework.jndi. JndiObjectFactoryBean"> <!-- 容器管理数据源的JNDI --> <property name="jndiName" value="jdbc/jpetstore"/> </bean> <!--定义Hibernate的SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3. LocalSessionFactoryBean"> <!-- 依赖注入SessionFactory所需的数据源,正是上文定义的dataSource Bean --> <property name="dataSource" ref="dataSource"/> <!-- mappingResources属性用来列出全部映射文件 --> <property name="mappingResources"> <list> <!-- 以下用来列出所有的PO映射文件 --> <value>lee/MyTest.hbm.xml</value> </list> </property> <!-- 定义Hibernate的SessionFactory的属性 --> <property name="hibernateProperties"> <props> <!-- 指定Hibernate的连接方言 --> <prop key="hibernate.dialect">org.hibernate.dialect. MySQLDialect</prop> <!-- 是否根据Hiberante映射创建数据表时,选择create、update、 create-drop --> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 使用JtaTransactionManager类,该类是PlatformTransactionManager接口, 针对采用数据源连接的特定实现 --> <!-- JtaTransactionManager不需要知道数据源,或任何其他特定资源, 因为使用容器的全局事务管理 --> <bean id="transactionManager" class="org.springframework.transaction.jta. JtaTransactionManager" /> </beans>
不论采用哪种持久层访问技术,只要使用JTA数据源,Spring事务管理器的配置都是一样的,因为它
们都采用的是全局事务管理。
可以看到,仅仅通过配置文件的修改,就可以在不同的事务管理策略间切换,即使从局部事务到全局
事务的切换。
提示:Spring所支持的事务策略非常灵活,Spring的事务策略允许应用程序在不同事务策略之间自由
切换,即使需要在局部事务策略和全局事务策略之间切换,只需要修改配置文件,而应用程序的代码
无须任何改变。这种灵活的设计,又何尝不是因为面向接口编程带来的优势,可见面向接口编程给应
用程序更好的适应性。
6.3.2 Spring事务策略的优势
虽然在上面的配置片段中,仅仅配置了JDBC局部事务管理器、Hibernate局部事务管理器、JDBC全局
事务管理器等。但Spring支持大部分持久化策略的事务管理器。
不论采用何种持久化策略,Spring都提供了一致的事务抽象,因此,应用开发者能在任何环境下,使
用一致的编程模型。无须更改代码,应用就可在不同的事务管理策略中切换。Spring同时支持声明式
事务管理和编程式事务管理。
使用编程式事务管理,开发者使用的是Spring事务抽象,而无须使用任何具体的底层事务API。
Spring的事务管理将代码从底层具体的事务API中抽象出来,该抽象可以使用在任何底层事务基础之
上。
使用声明式策略,开发者通常书写很少的事务管理代码,因此,不依赖Spring或任何其他事务API。
Spring的声明式事务无须任何额外的容器支持,Spring容器本身管理声明式事务。使用声明事务策略
,无须在业务代码中书写任何事务代码,可以让开发者更好地专注于业务逻辑的实现。Spring管理的
事务支持多个事务资源的跨越,但无法支持跨越远程调用的事务上下文传播。
6.3.3 使用TransactionProxyFactoryBean创建事务代理
Spring同时支持编程式事务策略和声明式事务策略,大部分时候,都推荐采用声明式事务策略,使用
声明事务策略的优势十分明显:
● 声明式事务能大大降低开发者的代码书写量。而且声明式事务几乎不需要影响应用的代码。因
此,无论底层事务策略如何变化,应用程序无须任何改变。
● 应用程序代码无须任何事务处理代码,可以更专注于业务逻辑的实现。
● Spring则可对任何POJO的方法提供事务管理,而且Spring的声明式事务管理无须容器的支持,
可在任何环境下使用。
● EJB的CMT无法提供声明式回滚规则。而通过配置文件,Spring可指定事务在遇到特定异常时自
动回滚。Spring不仅可在代码中使用setRollbackOnly回滚事务,也可在配置文件中配置回滚规则。
● 由于Spring采用AOP的方式管理事务,因此,可以在事务回滚动作中插入用户自己的动作,而不
仅仅是执行系统默认的回滚。
提示:本节不打算全面介绍Spring的各种事务策略,因此本节不会介绍编程式事务。如果读者需要更
全面了解Spring事务的相关方面,请参阅笔者所著的《Spring2.0宝典》 一书。
对于采用声明式事务策略,可以使用TransactionProxyFactoryBean来配置事务代理Bean。正如它的
类名所暗示的,它是一个工厂Bean,工厂Bean用于生成一系列的Bean实例,这一系列的Bean实例都是
Proxy。
可能读者已经想到了,既然TransactionProxyFactoryBean产生的是代理Bean,可见这种事务代理正
是基于Spring AOP组件的。配置TransactionProxyFactoryBean时,一样需要指定目标Bean。
每个TransactionProxyFactoryBean为一个目标Bean生成事务代理,事务代理的方法改写了目标Bean
的方法,就是在目标Bean的方法执行之前加入开始事务,在目标Bean的方法正常结束之前提交事务,
如果遇到特定异常则回滚事务。
TransactionProxyFactoryBean创建事务代理时,需要了解当前事务所处的环境,该环境属性通过
PlatformTransactionManager实例传入,而相关事务传入规则在TransactionProxy- FactoryBean的
定义中给出。
下面给出声明式事务配置文件的完整代码:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Spring配置文件的根元素,以及Spring配置文件的Schema信息 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 定义数据源Bean,使用C3P0数据源实现 --> <bean id="dataSource" class="com.mchange.v2.c3p0. ComboPooledDataSource" destroy-method="close"> <!-- 指定连接数据库的驱动 --> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <!-- 指定连接数据库的URL --> <property name="jdbcUrl" value="jdbc:mysql://localhost/j2ee"/> <!-- 指定连接数据库的用户名 --> <property name="user" value="root"/> <!-- 指定连接数据库的密码 --> <property name="password" value="32147"/> <!-- 指定连接数据库连接池的最大连接数 --> <property name="maxPoolSize" value="40"/> <!-- 指定连接数据库连接池的最小连接数 --> <property name="minPoolSize" value="1"/> <!-- 指定连接数据库连接池的初始化连接数 --> <property name="initialPoolSize" value="1"/> <!-- 指定连接数据库连接池的连接最大空闲时间 --> <property name="maxIdleTime" value="20"/> </bean> <!-- 定义Hibernate的SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3. LocalSessionFactoryBean"> <!-- 依赖注入SessionFactory所需的数据源,正是上文定义的dataSource --> <property name="dataSource" <ref="dataSource"/> <!-- mappingResources属性用来列出全部映射文件 --> <property name="mappingResources"> <list> <!-- 以下用来列出所有的PO映射文件 --> <value>lee/Person.hbm.xml</value> </list> </property> <!-- 定义Hibernate的SessionFactory属性 --> <property name="hibernateProperties"> <props> <!-- 指定Hibernate的连接方言 --> <prop key="hibernate.dialect">org.hibernate.dialect. MySQLDialect</prop> <!-- 是否根据Hiberante映射创建数据表时,选择create、update、 create-drop --> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 配置DAO Bean,该Bean将作为目标Bean使用 --> <bean id="personDAOTarget" class="lee.PersonDaoImpl"> <!-- 采用依赖注入来传入SessionFactory的引用 --> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!-- 配置Hibernate的事务管理器 --> <!-- 使用HibernateTransactionManager类,该类实现PlatformTransactionManager 接口,针对采用Hibernate持久化连接的特定实现 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3. HibernateTransactionManager"> <!-- HibernateTransactionManager Bean,它需要依赖注入一个SessionFactory Bean的引用 --> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!-- 配置personDAOTarget Bean的事务代理 --> <bean id="personDAO" class="org.springframework.transaction.interceptor. TransactionProxyFactoryBean"> <!-- 依赖注入PlatformTransactionManager的bean引用,此处使用 Hibernate的bean --> <!-- 局部事务器,因此transactionManager 传入Hibernate事务管理器的 引用 --> <property name="transactionManager" ref="transactionManager"/> <!-- 需要生成代理的目标bean --> <property name="target" ref="personDAOTarget"/> <!-- 指定事务属性 --> <property name="transactionAttributes"> <props> <!-- 以下部分为定义事务回滚规则 --> <prop key="insert*">PROPAGATION_REQUIRED, -MyCheckedException</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean> </beans>
在上面的定义文件中,没有对DAO对象采用Service层包装。通常情况下,DAO层上应有一层Service层
。事务代理则以Service层Bean为目标Bean。此处为了简化配置,TransactionProxyFactoryBean直接
以DAO bean作为目标bean,这一点不会影响事务代理的生成。
事务回滚规则部分定义了三个回滚规则:
第一个回滚规则表示所有以insert开始的方法,都应该满足该事务规则。PROPAGATION_REQUIRED事务
传播规则指明,该方法必须处于事务环境中,如果当前执行线程已处于事务环境下,则直接执行;否
则,启动新的事务然后执行该方法。该规则还指定,如果方法抛出MyCheckedException的实例及其子
类的实例,则强制回滚。MyCheckedException前的“-”表示强制回滚;“+”则表示强制提交,即某
些情况下,即使抛出异常也强制提交;
第二个回滚规则表示所有以update开头的方法,都遵守PROPAGATION_REQUIRED的事务传播规则;
第三个回滚规则表示除前面规定的方法外,其他所有方法都采用PROPAGATION_ REQUIRED事务传播规
则,而且只读。
常见的事务传播规则有如下几个:
● PROPAGATION_MANDATORY,要求调用该方法的线程必须处于事务环境中,否则抛出异常。
● PROPAGATION_NESTED,如果执行该方法的线程已处于事务环境下,依然启动新的事务,方法在
嵌套的事务里执行。如果执行该方法的线程序并未处于事务中,也启动新的事务,然后执行该方法,
此时与PROPAGATION_REQUIRED相同。
● PROPAGATION_NEVER,不允许调用该方法的线程处于事务环境下,如果调用该方法的线程处于事
务环境下,则抛出异常。
● PROPAGATION_NOT_SUPPORTED,如果调用该方法的线程处在事务中,则先暂停当前事务,然后执
行该方法。
● PROPAGATION_REQUIRED,要求在事务环境中执行该方法,如果当前执行线程已处于事务中,则
直接调用;如果当前执行线程不处于事务中,则启动新的事务后执行该方法。
● PROPAGATION_REQUIRES_NEW,该方法要求有一个线程在新的事务环境中执行,如果当前执行线
程已处于事务中,先暂停当前事务,启动新的事务后执行该方法;如果当前调用线程不处于事务中,
则启动新的事务后执行该方法。
● PROPAGATION_SUPPORTS,如果当前执行线程处于事务中,则使用当前事务,否则不使用事务。
程序里原来使用personDAO的地方,无须变化。因为,配置文件里将personDAO目标Bean的id改成
personDAOTarget,为TransactionProxyFactoryBean工厂Bean所产生的代理Bean命名为personDAO。
该代理Bean会包含原有personDAO的所有方法,而且为这些方法增加了不同的事务处理规则。
程序面向PersonDaoImpl类所实现的接口编程,TransactionProxyFactoryBean生成的代理Bean也会实
现TransactionProxyFactoryBean接口。因此,原有的程序中调用DAO组件的代码无须任何改变。程序
运行时,由事务代理完成原来目标Bean完成的工作。
事实上,Spring不仅支持对接口的代理,整合CGLIB后,Spring甚至可对具体类生成代理。只要设置
proxyTargetClass属性为true就可以。如果目标Bean没有实现任何接口,proxyTargetClass属性默认
被设为true,此时Spring会对具体类生成代理。当然,通常建议面向接口编程,而不要面向具体的实
现类编程。
6.3.4 使用继承简化事务配置
仔细观察配置文件中两个事务代理Bean的配置时,发现两个事务代理Bean的大部分配置完全相同,如
果配置文件中包含大量这样的事务代理Bean配置,配置文件将非常臃肿。考虑到大部分事务代理Bean
的配置都大同小异,可以使用Bean继承来简化事务代理的配置。
正如前面部分介绍的,Bean继承是将所有子Bean中相同的配置定义成一个模板,并将此模板Bean定义
成一个抽象Bean。考虑所有事务代理Bean中,有如下部分是大致相 同的:
● 事务代理Bean所使用的事务管理器。
● 事务传播规则。
因此,现在配置文件中定义如下的事务代理模板Bean,其配置代码如下:
<!-- 定义所有事务代理Bean的模板 --> <bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor. TransactionProxyFactoryBean"> <!-- 为事务代理Bean注入生成代理所需的PlatformTransactionManager实例 --> <property name="transactionManager" ref="transactionManager"/> <!-- 定义生成事务代理通用的事务属性 --> <property name="transactionAttributes"> <props> <!-- 所有的方法都应用PROPAGATION_REQUIRED的事务传播规则 --> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
而真正的事务代理Bean,则改为继承上面的事务模板Bean。考虑到将目标Bean定义在Spring容器中可
能增加未知的风险,因此将目标Bean定义成嵌套Bean。
<!-- 让事务代理Bean继承模板Bean --> <bean id="personDAO" parent="txProxyTemplate"> <!-- 这里采用嵌套Bean的方式来定义目标Bean,当然也可以引用已存在的Bean --> <property name="target"> <bean class="lee.personDAO"/> </property> </bean>
此时的personDAO Bean无须具体地定义事务属性,它将在其父Bean txProxyTemplate中获取事务定义
属性。此处采用嵌套Bean来定义目标Bean,因此,并未将目标Bean直接暴露在Spring的上下文中让其
他模块调用。当然,也可采用一个已经存在的Bean作为目标Bean;子Bean的事务属性定义,完全可覆
盖事务代理模板里的事务属性定义。如下例所示:
<!-- 让事务代理bean继承模板Bean --> <bean id="personDAO" parent="txProxyTemplate"> <!-- 这里,采用引用已存在的bean的方式来定义目标Bean --> <property name="target" ref ="personDAOTarget"/> <!-- 覆盖事务代理模板bean中的事务属性定义 --> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> </bean>
可见,采用Bean继承方式定义事务代理的方式,可以很好地简化事务代理的配置,可以避免配置事务
代理Bean时的冗余配置。
提示:使用Bean继承可以很好地简化事务代理Bean的配置,通过将各事务代理Bean共同的配置信息提
取成事务模板Bean,可以让实际的事务代理Bean的配置更加简洁;而且,配置方式相当直观。尽量将
目标Bean配置成嵌套Bean,这样的方式可以保证更好的内聚性。
如果读者还记得前面介绍的AOP知识,应该知道还有一种更加简洁的配置,就是利用Bean后处理器,
让Bean后处理器为容器中其他Bean自动创建事务代理。
6.3.5 使用自动创建代理简化事务配置
回顾6.2.6节和6.2.7节,读者可能已经想到如何自动创建代理。是的,正是通过6.2.6节和6.2.7节所
给出的两个自动代理创建类来生成事务代理。
正如前文已经提到的,使用BeanNameAutoProxyCreator和DefaultAdvisorAutoProxy- Creator来创建
代理时,并不一定是创建事务代理,关键在于传入的拦截器,如果传入事务拦截器,将可自动生成事
务代理。
下面是使用BeanNameAutoProxyCreator自动生成事务代理的配置文件:
<?xml version="1.0" encoding="GBK"?> <!-- 指定Spring配置文件的根元素,以及相应的Schema信息 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 定义数据源Bean,使用C3P0数据源实现 --> <bean id="dataSource" class="com.mchange.v2.c3p0. ComboPooledDataSource" destroy-method="close"> <!-- 指定连接数据库的驱动 --> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <!-- 指定连接数据库的URL --> <property name="jdbcUrl" value="jdbc:mysql://localhost/j2ee"/> <!-- 指定连接数据库的用户名 --> <property name="user" value="root"/> <!-- 指定连接数据库的密码 --> <property name="password" value="32147"/> <!-- 指定连接数据库连接池的最大连接数 --> <property name="maxPoolSize" value="40"/> <!-- 指定连接数据库连接池的最小连接数 --> <property name="minPoolSize" value="1"/> <!-- 指定连接数据库连接池的初始化连接数 --> <property name="initialPoolSize" value="1"/> <!-- 指定连接数据库连接池的连接最大空闲时间 --> <property name="maxIdleTime" value="20"/> </bean> <!-- 使用JDBC的局部事务策略 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSource- TransactionManager"> <!-- 为事务管理器注入所需的数据源Bean --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 配置目标Bean,该目标Bean将由Bean后处理器自动生成代理 --> <bean id="test1" class="lee.TransactionTestImpl"> <!-- 依赖注入目标Bean所必需的数据源Bean --> <property name="ds" ref="dataSource"/> </bean> <!-- 配置目标Bean,该目标Bean将由Bean后处理器自动生成代理 --> <bean id="test2" class="lee.TestImpl"> <!-- 依赖注入目标Bean所必需的数据源Bean --> <property name="ds" ref="dataSource"/> </bean> <!-- 配置事务拦截器Bean --> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor. TransactionInterceptor"> <!-- 事务拦截器bean需要依赖注入一个事务管理器 --> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <!-- 下面定义事务传播属性 --> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <!-- 定义BeanNameAutoProxyCreator的Bean后处理器 --> <bean class="org.springframework.aop.framework.autoproxy. BeanNameAutoProxyCreator"> <!-- 指定对满足哪些bean name的bean自动生成业务代理 --> <property name="beanNames"> <!-- 下面是所有需要自动创建事务代理的Bean --> <list> <value>test1</value> <value>test2</value> </list> <!-- 此处可增加其他需要自动创建事务代理的Bean --> </property> <!-- 下面定义BeanNameAutoProxyCreator所需的拦截器 --> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> <!-- 此处可增加其他新的Interceptor --> </list> </property> </bean> </beans>
如果配置文件中仅有两个目标Bean,可能不能很清楚地看出这种自动创建代理配置方式的优势,但如果有更多目标Bean需要自动创建事务代理,则可以很好地体会到这种配置方式的优势:配置文件只需
要简单地配置目标Bean,然后在BeanNameAutoProxyCreator配置中增加一行即可。
提示:使用BeanNameAutoProxyCreator可以自动创建事务代理,使用DefaultAdvisor-
AutoProxyCreator也可自动创建事务代理。关于后一个Bean后处理器的配置方式,请参看前面6.2.7节的内容。
发表评论
-
基于Spring AOP 注解缓存Demo [附源码]
2016-08-27 19:20 0一. 现在的缓存: 现在APP局部或多或少都使用了缓存, ... -
Ibatis+Spring整合实例Demo+源码
2011-12-02 21:03 81561. 单独整合ibatis ibatis和hibernate ... -
纯Struts2登录实例Demo+源码
2011-12-01 17:12 22955接触到别人的新的项目, 不得不研究下Struts2了. 用st ... -
Spring3+Hibernate3+Struts1流程总结
2011-05-14 17:27 1926SSH结束之后,NOVA团队就基于SSH实现了NOVA音乐视频 ... -
Spring3整合Hibernate3
2011-05-14 17:14 70646.5 Spring整合Hibernate 时至今日,可能极 ... -
Spring整合Struts
2011-05-14 17:06 12076.4 Spring整合Struts 虽然Spring也 ... -
Spring的AOP
2011-05-14 16:50 12136.2 Spring的AOP AOP(Aspe ... -
<<Hibernate基础教程>>总结
2011-05-14 16:34 1539一.总体概述: Hibernate 的底层也是由JDBC 实现 ... -
<<深入浅出Struts>>总结
2011-05-14 16:28 1175一.纵观本书:基本原理是实现控制器的功能和展示层的标签.for ...
相关推荐
矢量边界,行政区域边界,精确到乡镇街道,可直接导入arcgis使用
毕业设计
毕业设计
经验贝叶斯EB的简单例子
智慧园区,作为现代城市发展的新形态,旨在通过高度集成的信息化系统,实现园区的智能化管理与服务。该方案提出,利用智能手环、定制APP、园区管理系统及物联网技术,将园区的各类设施与设备紧密相连,形成一个高效、便捷、安全的智能网络。从智慧社区到智慧酒店,从智慧景区到智慧康养,再到智慧生态,五大应用板块覆盖了园区的每一个角落,为居民、游客及工作人员提供了全方位、个性化的服务体验。例如,智能手环不仅能实现定位、支付、求助等功能,还能监测用户健康状况,让科技真正服务于生活。而智慧景区的建设,更是通过大数据分析、智能票务、电子围栏等先进技术,提升了游客的游玩体验,确保了景区的安全有序。 尤为值得一提的是,方案中的智慧康养服务,展现了科技对人文关怀的深刻体现。通过智慧手环与传感器,自动感知老人身体状态,及时通知家属或医疗机构,有效解决了“空巢老人”的照护难题。同时,智慧生态管理系统的应用,实现了对大气、水、植被等环境要素的实时监测与智能调控,为园区的绿色发展提供了有力保障。此外,方案还提出了建立全域旅游营销平台,整合区域旅游资源,推动旅游业与其他产业的深度融合,为区域经济的转型升级注入了新的活力。 总而言之,这份智慧园区建设方案以其前瞻性的理念、创新性的技术和人性化的服务设计,为我们展示了一个充满智慧与活力的未来园区图景。它不仅提升了园区的运营效率和服务质量,更让科技真正融入了人们的生活,带来了前所未有的便捷与舒适。对于正在规划或实施智慧园区建设的决策者而言,这份方案无疑提供了一份宝贵的参考与启示,激发了他们对于未来智慧生活的无限遐想与憧憬。
数学建模相关主题资源2
内容概要:本文围绕SQL在求职和实际工作中的应用展开,详细解析了SQL的重要性及其在不同行业中不可替代的地位。文章首先强调了SQL作为“一切数据工作的起点”,是数据分析、数据挖掘等领域必不可少的技能,并介绍了SQL与其他编程语言在就业市场的对比情况。随后重点探讨了SQL在面试过程中可能出现的挑战与应对策略,具体涉及到询问澄清问题、正确选择JOIN语句类型、恰当使用GROUP BY及相关过滤条件的区别、理解和运用窗口函数等方面,并给出了详细的实例和技巧提示。另外提醒面试者要注意重复值和空值等问题,倡导与面试官及时沟通。文中引用IEEE Spectrum编程语言排行榜证明了SQL不仅广泛应用于各行各业,在就业市场上也最受欢迎。 适用人群:从事或打算转入数据科学领域(包括但不限于数据分析师、数据科学家、数据工程师等职业方向),并对掌握和深入理解SQL有一定需求的专业人士,尤其是正准备涉及SQL相关技术面试的求职者。 使用场景及目标:帮助用户明确在面对复杂的SQL查询题目时能够更加灵活应对,提高解题效率的同时确保准确性;同时让用户意识到SQL不仅仅是简单的数据库查询工具,而是贯穿整个数据处理流程的基础能力之一,进而激发他们进一步探索的热情。 其他说明:SQL在性能方面优于Excel尤其适用于大规模数据操作;各知名企业仍将其视为标准数据操作手段。此外还提供了对初学者友好的建议,针对留学生普遍面临的难题如零散的学习资料、昂贵且效果不佳的付费教程以及难以跟上的纯英教学视频给出了改进的方向。
COMSOL仿真揭示石墨烯临界耦合光吸收特性:费米能级调控下的光学性能探究,COMSOL仿真揭示石墨烯临界耦合光吸收特性:费米能级调控下的光学性能探究,COMSOL 准 BIC控制石墨烯临界耦合光吸收。 COMSOL 光学仿真,石墨烯,光吸收,费米能级可调下图是仿真文件截图,所见即所得。 ,COMSOL; 准BIC; 石墨烯; 临界耦合光吸收; 光学仿真; 费米能级可调。,COMSOL仿真:石墨烯光吸收的BIC控制与费米能级调节
Labview与Proteus串口仿真下的温度采集与报警系统:Keil单片机程序及全套视频源码解析,Labview与Proteus串口仿真温度采集及上位机报警系统实战教程:设定阈值的Keil程序源码分享,labview 和proteus 联合串口仿真 温度采集 上位机报警 设定阈值单片机keil程序 整套视频仿真源码 ,关键词:LabVIEW;Proteus;串口仿真;温度采集;上位机报警;阈值设定;Keil程序;视频仿真源码。,LabVIEW与Proteus联合串口仿真:温度采集与报警系统,Keil程序与阈值设定全套视频源码
整车性能目标书:涵盖燃油车、混动车及纯电动车型的十六个性能模块目标定义模板与集成开发指南,整车性能目标书:涵盖燃油车、混动车及纯电动车型的十六个性能模块目标定义模板与集成开发指南,整车性能目标书,汽车性能目标书,十六个性能模块目标定义模板,包含燃油车、混动车型及纯电动车型。 对于整车性能的集成开发具有较高的参考价值 ,整车性能目标书;汽车性能目标书;性能模块目标定义模板;燃油车;混动车型;纯电动车型;集成开发;参考价值,《汽车性能模块化目标书:燃油车、混动车及纯电动车的集成开发参考》
熵值法stata代码(含stata代码+样本数据) 面板熵值法是一种在多指标综合评价中常用的数学方法,主要用于对不同的评价对象进行量化分析,以确定各个指标在综合评价中的权重。该方法结合了熵值理论和面板数据分析,能够有效地处理包含多个指标的复杂数据。
“电子电路”仿真资源(Multisim、Proteus、PCB等)
在 GEE(Google Earth Engine)中,XEE 包是一个用于处理和分析地理空间数据的工具。以下是对 GEE 中 XEE 包的具体介绍: 主要特性 地理数据处理:提供强大的函数和工具,用于处理遥感影像和其他地理空间数据。 高效计算:利用云计算能力,支持大规模数据集的快速处理。 可视化:内置可视化工具,方便用户查看和分析数据。 集成性:可以与其他 GEE API 和工具无缝集成,支持多种数据源。 适用场景 环境监测:用于监测森林砍伐、城市扩展、水体变化等环境问题。 农业分析:分析作物生长、土地利用变化等农业相关数据。 气候研究:研究气候变化对生态系统和人类活动的影响。
内容概要:本文介绍了C++编程中常见指针错误及其解决方案,并涵盖了模板元编程的基础知识和发展趋势,强调了高效流操作的最新进展——std::spanstream。文章通过一系列典型错误解释了指针的安全使用原则,强调指针初始化、内存管理和引用安全的重要性。随后介绍了模板元编程的核心特性,展示了编译期计算、类型萃取等高级编程技巧的应用场景。最后,阐述了C++23中引入的新特性std::spanstream的优势,对比传统流处理方法展现了更高的效率和灵活性。此外,还给出了针对求职者的C++技术栈学习建议,涵盖了语言基础、数据结构与算法及计算机科学基础领域内的多项学习资源与实战练习。 适合人群:正在学习C++编程的学生、从事C++开发的技术人员以及其他想要深入了解C++语言高级特性的开发者。 使用场景及目标:帮助读者掌握C++中的指针规则,预防潜在陷阱;介绍模板元编程的相关技术和优化方法;使读者理解新引入的标准库组件,提高程序性能;引导C++学习者按照有效的路径规划自己的技术栈发展路线。 阅读建议:对于指针部分的内容,应当结合实际代码样例反复实践,以便加深理解和记忆;在研究模板元编程时,要从简单的例子出发逐步建立复杂模型的理解能力,培养解决抽象问题的能力;而对于C++23带来的变化,则可以通过阅读官方文档并尝试最新标准特性来加深印象;针对求职准备,应结合个人兴趣和技术发展方向制定合理的学习计划,并注重积累高质量的实际项目经验。
JNA、JNI, Java两种不同调用DLL、SO动态库方式读写FM1208 CPU卡示例源码,包括初始化CPU卡、创建文件、修改文件密钥、读写文件数据等操作。支持Windows系统、支持龙芯Mips、LoongArch、海思麒麟鲲鹏飞腾Arm、海光兆芯x86_Amd64等架构平台的国产统信、麒麟等Linux系统编译运行,内有jna-4.5.0.jar包,vx13822155058 qq954486673
内容概要:本文全面介绍了Linux系统的各个方面,涵盖入门知识、基础操作、进阶技巧以及高级管理技术。首先概述了Linux的特点及其广泛的应用领域,并讲解了Linux环境的搭建方法(如使用虚拟机安装CentOS),随后深入剖析了一系列常用命令和快捷键,涉及文件系统管理、用户和权限设置、进程和磁盘管理等内容。此外,还讨论了服务管理的相关指令(如nohup、systemctl)以及日志记录和轮替的最佳实践。这不仅为初学者提供了一个完整的知识框架,也为中级和高级用户提供深入理解和优化系统的方法。 适合人群:适用于有意深入了解Linux系统的学生和专业技术人员,特别是需要掌握服务器运维技能的人群。 使用场景及目标:本文适合初次接触Linux的操作员了解基本概念;也适合作为培训教材,指导学生逐步掌握各项技能。对于有一定经验的技术人员而言,则可以帮助他们巩固基础知识,并探索更多的系统维护和优化可能性。 阅读建议:建议按照文章结构循序渐进地学习相关内容,尤其是结合实际练习操作来加深记忆和理解。遇到复杂的问题时可以通过查阅官方文档或在线资源获得更多帮助。
内容概要:本文档详细介绍了企业在规范运维部门绩效管理过程中所建立的一套绩效考核制度。首先阐述了绩效考核制度设立的目的为确保绩效目标得以衡量与追踪,并确保员工与公司共同成长与发展。其次规定范围覆盖公司所有在职员工,并详细列明了从总经理到一线员工在内的不同角色的职责范围。再则描述了完整的绩效工作流程,即从年初开始制定绩效管理活动计划,经过与每个员工制定具体的绩效目标,在绩效考核周期之内对员工的工作进展和问题解决状况进行持续的监督跟进,并且在每周期结束前完成员工绩效的评估和反馈工作,同时利用绩效评估结果对员工作出保留或异动的相关决定,最后进行绩效管理活动总结以为来年提供参考。此外还强调了整个过程中必要的相关文档保存,如员工绩效评估表。 适合人群:企业管理层,HR专业人士及对现代企业内部运营管理感兴趣的读者。 使用场景及目标:①管理层需要理解如何规范和有效实施企业内部绩效管理,以提高公司运营效率和员工满意度;②HR人士可以通过参考此文档来优化自己公司的绩效管理体系;③对企业和组织管理有兴趣的研究员亦可借鉴。 阅读建议:读者应重点关注各个层级管理者和员工在整个流程中的角色和责任,以期更好地理解
基于MATLAB Simulink的LCL三相并网逆变器仿真模型:采用交流电流内环PR控制与SVPWM-PWM波控制研究,基于MATLAB Simulink的LCL三相并网逆变器仿真模型研究:采用比例谐振控制与交流SVPWM控制策略及参考文献解析,LCL_Three_Phase_inverter:基于MATLAB Simulink的LCL三相并网逆变器仿真模型,交流电流内环才用PR(比例谐振)控制,PWM波采用SVPWM控制,附带对应的参考文献。 仿真条件:MATLAB Simulink R2015b,前如需转成低版本格式请提前告知,谢谢。 ,LCL三相并网逆变器; LCL_Three_Phase_inverter; MATLAB Simulink; PR控制; SVPWM控制; 仿真模型; 参考文献; 仿真条件; R2015b版本,基于PR控制与SVPWM的LCL三相并网逆变器Simulink仿真模型研究
内点法求解标准节点系统最优潮流计算的稳定程序,注释清晰,通用性强,内点法用于标准节点系统的最优潮流计算:稳定、通用且注释清晰的matlab程序,内点法最优潮流程序matlab 采用内点法对14标准节点系统进行最优潮流计算,程序运行稳定,注释清楚,通用性强 ,内点法; 最优潮流程序; MATLAB; 14标准节点系统; 稳定运行; 清晰注释; 通用性强。,Matlab内点法最优潮流程序:稳定高效,通用性强,适用于14节点系统
17suiea3.apk?v=1741006890849