百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Spring基于AOP的事务管理(spring事务管理aop配置)

lipiwang 2024-11-17 13:25 9 浏览 0 评论

原文地址:https://www.cnblogs.com/zhanglei93/p/6240840.html

作者:best.lei

  • 事务

事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务就将回到最开始的状态,仿佛一切都没发生过。例如,老生常谈的转账问题,从转出用户的总存款中扣除转账金额和增加转出用户的账户金额是一个完整的工作单元,如果只完成扣除或者增加都会导致错误,造成损失,而事务管理技术可以避免类似情况的发生,保证数据的完整性和一致性。同样在企业级应用程序开发过程中,事务管理技术也是必不可少的。

事务有四个特性:ACID

  1. 原子性(Atomicity):事务是一个原子操作,有一系列动作组成。原子性保证所有动作都完成,或者不执行任何动作。
  2. 一致性(Consistency):一旦事务完成(不论成败),系统必须确保它所建模的业务处于一致的状态。
  3. 隔离性(Isolation):可能有很多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
  4. 持久性(Durability):一旦事务完成,无论系统发生生什么系统错误,它的结果都不会受到影响,保证能从系统崩溃中恢复过来,通常事务的结果会被写入到持久化存储器中。

Spring事务是基于面向切面编程(Aspect Oriented Programming,AOP)实现的(文中会简单讲解AOP)。Spring的事务属性分别为传播行为、隔离级别、回滚规则、只读和事务超时属性,所有这些属性提供了事务应用方法和描述策略。如下我们介绍Spring事务管理的三个核心接口。

  • 核心接口
  1. TransactionDefinition接口是事务描述对象,提供获取事务相关信息的方法。
  2. PlatformTransactionManager接口是平台事务管理器,用于管理事务。
  3. TransactionStatus接口是事务的状态,描述了某一时间点上事务的状态信息。

关于事务管理器PlatformTransactionManager的详细介绍见:http://www.mamicode.com/info-detail-1248286.html。

  • Spring AOP

面向切面编程(Aspect Oriented Programing,AOP)采用横向抽取机制,是面向对象编程(Object Oriented Programing,OOP)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能、权限管理、异常处理等,该类功能往往横向地散布在核心代码当中,这种散布在各处的无关代码被称为横切。AOP恰是一种横切技术,解剖开封装对象的内部,将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为Aspect(切面),所谓切面,简单的说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

AOP术语

  1. 连接点(Joinpoint):被拦截到的点,该连接点可以是被拦截到的方法、字段或者构造器;
  2. 切入点(Pointcut):指要对哪些连接点进行拦截,即被拦截的连接点;
  3. 通知(Advice):指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知;
  4. 目标(Target):代理的目标对象;
  5. 织入(Weaving):把增强的代码应用到目标上,生成代理对象的过程;
  6. 切面(Aspect):切入点和通知的集合。
  • 项目实践

接下来我们就利用Spring的事务管理实现如上例子中所述的转账案例,利用mysql数据库创建名称为User的数据库,在User数据库中创建两张表:用户信息表(t_user)、用户存款表(account),然后实现用户A向用户B转账,更新数据库表信息,如果转账失败,则数据库信息自动返回转账前的状态。

在Eclipse下创建Java工程,其中必要的jar包以及工程中的类如下所示,jar包的下载地址为:Spring_AOP.zip。

项目中的类介绍如下:

用户类(User):包含用户基本信息(id,name,password),以及基本信息的get/set方法。

创建用户的工厂(UserFactory):创建用户的工厂,创建具体用户对象。

用户数据访问接口(UserDao):定义对用户表(t_user)的基本操作(增、删、改、查)。

用户数据访问实现类(UserDaoImpl):实现接口(UserDao)中定义的方法。

public class UserDaoImpl implements UserDao{
 private JdbcTemplate jdbcTemplate;
 
 public void setJdbcTemplate(JdbcTemplate jdbc){
 this.jdbcTemplate = jdbc;
 }
 @Override
 public int addUser(User user) {
 // TODO Auto-generated method stub
 String sql = "insert into t_user(userid,username,password)values(?,?,?)";
 Object[] obj = new Object[]{
 user.getUserID(),
 user.getUserName(),
 user.getPassword()
 };
 return this.execute(sql, obj);
 }
 @Override
 public int updateUser(User user) {
 // TODO Auto-generated method stub
 String sql = "update t_user set username=?,password=? where userid=?";
 Object[] obj = new Object[]{
 user.getUserName(),
 user.getPassword(),
 user.getUserID()
 };
 return this.execute(sql, obj);
 }
 @Override
 public int deleteUser(User user) {
 // TODO Auto-generated method stub
 String sql = "delete from t_user where userid=?";
 Object[] obj = new Object[]{
 user.getUserID()
 };
 return this.execute(sql, obj);
 }
 private int execute(String sql, Object[] obj){
 return this.jdbcTemplate.update(sql, obj);
 }
 @Override
 public User findUserByID(int id) {
 // TODO Auto-generated method stub
 String sql = "select * from t_user where userid=?";
 RowMapper<User> rowMapper = new BeanPropertyRowMapper(User.class);
 return this.jdbcTemplate.queryForObject(sql, rowMapper, id);
 }
 @Override
 public List<User> findAllUser() {
 // TODO Auto-generated method stub
 String sql = "select * from t_user";
 RowMapper<User> rowMapper = new BeanPropertyRowMapper(User.class);
 return this.jdbcTemplate.query(sql, rowMapper);
 }
}

存款访问接口(AccountDao):定义对存款表(account)的基本操作。

public interface AccountDao {
 public void addAccount(int id, double account);
 public void inAccount(int id, double account);
 public void outAccount(int id, double account);
}

存款访问实现类(AccountDaoImpl):实现接口(AccountDao)定义的方法。

存款服务层方法接口(AccountService):定义暴露对外的,提供给用户访问的接口。

public interface AccountService {
 /*
 * 转账,实现从outUser转出account金额的钱到inUser
 */
 public void transfer(User outUser, User inUser, double account);
}

存款服务层方法实现类(AccountServiceImpl):实现接口(AccountService)中定义的方法。

创建数据库表的类(CreateTables)

客户端类(Client)如下:

最后的也是我们实现Spring AOP最关键的配置文件JdbcTemplateBeans.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:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
 <!-- 配置数据源 --> 
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
 <!-- 数据库驱动 -->
 <property name="driverClass" value="com.mysql.jdbc.Driver"/>
 <!-- 连接数据库的URL -->
 <property name="jdbcUrl" value="jdbc:mysql://localhost/User"/>
 <!-- 连接数据库的用户名 -->
 <property name="user" value="root"/>
 <!-- 连接数据的密码 -->
 <property name="password" value="123"/>
 </bean>
 <!-- 配置JDBC模板 -->
 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
 <!-- 默认必须使用数据源 -->
 <property name="dataSource" ref="dataSource"/>
 </bean>
 <bean id="createTables" class="com.jdbc.CreateTables">
 <!-- 通过setter方法实现JdbcTemplate对象的注入 -->
 <property name="jdbcTemplate" ref="jdbcTemplate"/>
 </bean>
 <bean id="userDao" class="com.jdbc.UserDaoImpl">
 <property name="jdbcTemplate" ref="jdbcTemplate"/>
 </bean>
 <bean id="accountDao" class="com.jdbc.AccountDaoImpl">
 <property name="jdbcTemplate" ref="jdbcTemplate"/>
 </bean>
 <bean id="accountService" class="com.jdbc.AccountServiceImpl">
 <property name="accountDao" ref="accountDao"/>
 </bean>
 <!-- 事务管理器,依赖于数据源 -->
 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource"/>
 </bean>
 <!-- 编写通知:对事务进行增强,需要对切入点和具体执行事务细节 -->
 <tx:advice id="txAdvice" transaction-manager="txManager">
 <tx:attributes>
 <!-- <tx:method> 给切入点添加事务详情
 name:方法名称, *表示任意方法, do* 表示以do开头的方法
 propagation:设置传播行为
 isolation:隔离级别
 read-only:是否只读 -->
 <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
 </tx:attributes>
 </tx:advice>
 <!-- aop编写,让Spring自动对目标进行代理,需要使用AspectJ的表达式 -->
 <aop:config>
 <!-- 切入点 -->
 <aop:pointcut expression="execution(* com.jdbc.AccountServiceImpl.*(..))" id="txPointCut"/>
 <!-- 切面:将切入点和通知整合 -->
 <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
 </aop:config> 
</beans>

启动mysql数据库创建名称为User的数据库,然后运行该Java工程,输出如下所示:

然后去mysql的User数据库中查看刚才生成的表如下:

从控制台输出中,我们得知在代码(int i = 1 / 0)处发生了异常,而在异常发生之前,转出方存款已经发生变化,而通过查看account表发现金额还是输入的状态,User1的金额并没有减少,从而实现了在系统出现异常情况下,事务的回滚。本来想写到这里就结束的,但是总感觉没有把AOP说的特别透彻,于是想通过在转账前后增加日志的方式对AOP做进一步的讲解。

在原来项目的基础上,增加一个日志打印类(LogHandler),该类代码如下:

当然啦,还需要在XML配置文件中增加配置信息:

然后将AccountServiceImpl类中transfer方法中异常语句(int i = 1 / 0)注释掉,将Client类中的创建表、添加表项的代码也注释掉,再次执行主函数,则显示日志输出,查看转账前后数据库表状态。表如下:

如上就是对Spring AOP事务管理一个简单的介绍,希望能对读者产生一点帮助。

相关推荐

微软Office Open XML中的数字签名漏洞

MicrosoftOffice是最广泛使用的办公文档应用程序之一。对于重要文件,如合同和发票,可以对其内容进行签名,以确保其真实性和完整性。自2019年以来,安全研究人员发现了针对PDF和ODF等其...

Javaweb知识 day12 XML(javaweb中xml作用)

一、XML:1.1概念:ExtensibleMarkupLanguage可扩展标记语言*可扩展:标签都是自定义的。<user><student>1.2功能:...

易筋洗髓功——内外同修方可致远(易筋洗髓功口诀)

达摩祖师所传易筋、洗髓两经,一分为二,二实为一,无非以方便法门接引众生,而归于慈悲清净之心地。修炼《易筋经》是为强身健体,修炼《洗髓经》是为修心养性,此二者相辅相成,内外兼修,缺一不可。这是一套传统中...

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 4

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 5

道家洗髓功修炼要义,洗髓功如何做到丹田聚气?

不管是道家洗髓功,还是洗髓经,其修炼的关键点就在于得气、行气、聚气...那么,作为洗髓功修炼者,具体该怎么做呢?在实际修炼中,就洗髓功的修炼方法来讲,我们可以简单的归纳为修炼三部曲,其具体表现如下:一...

「清风聊练功」师门传我易筋经:聊聊我的学习经历和正身图感受

一个人的眼界认识,是随着是自身的知识积累和水平不断成长的。开篇为什么要说这么一句呢?是从我的学习经历上感受明显的这句话:一处不到一处迷。我们学传统武术,内功功法,也是从小白到明白一步步走的,走的越远,...

内功外练功介绍(练内功 外功)

这里介绍我练习的两套动功心得体会。是老道长的八部金刚功、长寿功和增演易筋洗髓经。八部金刚功外练奇经八脉,练出健康强壮的好身体还是可以的,长寿功也是内练功法。这部功法很好的预防效果。这个大家都认同的。说...

孔德易筋洗髓大全注解(下)(孔德易筋经教学视频)

...

《增演易筋洗髓内功图说》17卷(1930年(清)周述官撰 1

少林空悟老师珍藏

国术典籍:《增演易筋洗髓内功图说》【2024年8月编校】

《增演易筋洗髓内功图说》系养生气功著作,全书共十八卷。清周述官编撰于光绪二十一年(1895年)。清光绪十九年(1893年),僧人静一空悟将少林功法传授于周述官,并将《增益易筋洗髓内功图说》十二卷(按,...

小说:自媒体小白的修道之路-洗髓(自媒体小白运营技巧)

谁应了谁的劫,谁又变成了谁的执念。当沧海遗忘了桑田,这世间又多了一个不回家的人!异域空间中,知生缓缓起身,目光扫了一下小帝后,又转身看向画板上的那朵白色蒲公英,自言道:“白瑛,这一世我们莫要再辜负了!...

这才是少林洗髓经真相:它是静功和导引术与八段锦暗合

不少朋友误解易筋经和洗髓经,将其简单归为强力呼吸的吐纳功以及为了提升房中的关窍功。事实上易筋经和洗髓经是两部功法:易筋经主要为炼体,包含以膜论为核心的十二月怕打筋膜法,以及辅助的呼吸、导引功法;洗髓经...

孔德易筋洗髓大全注解(上)(孔德易筋经洗髓经视频)

...

洗髓经传承与心得(二)(《洗髓经》)

...

取消回复欢迎 发表评论: