广州大型网站建设公司排名,地产网站设计,信息技术网站开发,c 做游戏的网站教学文章目录1. 定义Spring Bean篇1.1 定义Spring Bean的几种方式1.1.1 XML文件定义Spring Bean1.1.2 JavaConfig定义Spring Bean1.1.3 Component注解定义SpringBean1.2 装配Spring Bean的四种常用方式1.2.1 手动装配 XML文件1.2.2 自动装配 XML文件1.2.3 手动装配 JavaConfig文…
文章目录1. 定义Spring Bean篇1.1 定义Spring Bean的几种方式1.1.1 XML文件定义Spring Bean1.1.2 JavaConfig定义Spring Bean1.1.3 Component注解定义SpringBean1.2 装配Spring Bean的四种常用方式1.2.1 手动装配 XML文件1.2.2 自动装配 XML文件1.2.3 手动装配 JavaConfig文件1.2.4 自动装配 注解2. Spring Bean注册到容器中2.1 实例化生成普通对象2.1.1 通过反射机制获取构造器通过构造器创建普通对象2.1.2 属性注入2.1.3 初始化2.1.4 初始化后生成代理对象2.1.5 注册销毁2.1.6 将普通对象或者代理对象加入单例池中3. Spring注解开发3.1 使用注解开发前需要做的配置3.1.1 使用注解开发必须要保证导入aop包3.1.2 使用注解需要导入context约束、增加注解的支持3.2 了解常用的注解3.2.1 Component、Mapper、Service、Controller3.2.2 Bean3.2.3 ComponentScan3.2.4 Import3.2.5 Autowired和Qualifier3.2.6 Resource3.2.7 Value4. Spring事务4.1 本质与原理讲解Spring事务是基于AOP实现的AOP是基于继承原理的。4.2 事务失效场景4.2.1 访问权限问题private4.2.2 final修饰4.2.3 未被Spring管理4.2.4 表不支持事务4.2.5 未开启事务4.2.6 方法内部调用4.2.7 错误的传播特性4.2.8 自己吞了异常4.2.9 手动抛了别的异常4.2.10 事务嵌套回滚多了4.2.11 大事务4.3 编程式事务1. 定义Spring Bean篇
1.1 定义Spring Bean的几种方式
1.1.1 XML文件定义Spring Bean
基本类型注册
Data
NoArgsConstructor
AllArgsConstructor
public class Student{private String name;private Address address;private String[] books;private ListString hobbys;private MapString String card;private SetString games;private String wife;private Properties info;
}setter方法注入property的name属性填写的不是属性的名称而是set方法去除set然后将第一个字符小写后的结果
bean idstudent classcom.kuang.pojo.Student!--1. 普通注入--property namename value狂神说/!--2. 数组注入--property namebooksarrayvalue红楼梦/valuevalue西游记/valuevalue水浒传/value/array/property!--3. List注入--property namehobbyslistvalue看书/valuevalue听歌/valuevalue打球/value/list/property!--4. Map注入--property namecardmapentry key“身份证” value“12315454512312”/entry key“银行卡” value“15465415123156”//map/property!--5. 数组注入--property namegamessetvalue红楼梦/valuevalue西游记/valuevalue水浒传/value/set/property!--6. 空值注入--property namewifenull//property!--7. Properties注入--property nameinfopropsprop keydriver20190525/propprop keyurl男/propprop keyusernameroot/propprop keypassword123456/prop/props/property
/bean类装配 !--csBean类有两个属性title和author--bean namecdBean classcom.my.spring.bean.CDBeanproperty nametitle valueThe World!!/property nameauthor valueMr.D//bean !--csPlayer类有一个属性cdBean--!--对csPlayer的属性csBean进行依赖注入称为Bean装配或者依赖关系注入--bean namecdPlayer classcom.my.spring.service.impl.CDPlayerImplproperty namecdBean refcdBean//bean有参构造方法注入
!--有参构造方法1--bean idhello classcom.kuang.pojo.Helloconstructor-arg index0 value方法1//bean
!--有参构造方法2--bean idhello classcom.kuang.pojo.Helloconstructor-arg typejava.lang.String value方法2//bean
!--有参构造方法3--bean idhello classcom.kuang.pojo.Helloconstructor-arg namename value方法3//bean扩展注入
!--p命名空间注入--
!--先在beans框架中加入支持xmlns:phttp://www/springframework.org/schema/p--
!--p命名空间注入可以直接注入属性的值property--
bean iduser classcom.kuang.pojo.User p:name小李 p:age10/!--c命名空间注入--
!--先在beans框架中加入支持xmlns:chttp://www/springframework.org/schema/c--
!--其次使用c注入的Bean必须存在有参构造器--
!--c命名空间注入通过构造器注入construct-args--
bean iduser classcom.kuang.pojo.User c:name小李 c:age10/Bean的作用域
单例模式Spring默认机制从Spring容器中get的每个对象都是同一个对象。
// bean iduser classcom.kuang.pojo.User scopesingleton/ApplicationContext context new ClassPathXmlApplicationContext(userbeans.xml);
User user1 context.getBean(user);
User user2 context.getBean(user);
System.out.println(user1user2); //true原型模式每次从容器中get的时候都会产生一个新对象
// bean iduser classcom.kuang.pojo.User scopeprototype/ApplicationContext context new ClassPathXmlApplicationContext(userbeans.xml);
User user1 context.getBean(user);
User user2 context.getBean(user);
System.out.println(user1user2); //false别名
!--别名如果添加了别名我们可以使用别名获取这个对象--
alias nameuser aliasuserNew!--idbean的唯一标识符也就是相当于我们学的对象名classbean对象所对应的全限定名包名类型name也是别名而且那么可以同时取多个别名
--bean iduser classcom.kuang.pojo.user nameuser1,user2,user3property namename value狂神说//beanImport 如果导入的文件中bean重名了那么就会把重名的bean合并成一个所以不会因为不同的bean.xml存在重名而发生冲突
import resourcebeans1.xml/
import resourcebeans2.xml/
import resourcebeans3.xml/1.1.2 JavaConfig定义Spring Bean
Data
NoArgsConstructor
AllArgsConstructor
public class User {Value(测试名字)public String name;
} Configuration
public class JavaConfig {Beanpublic User getUser() {return new User();} }1.1.3 Component注解定义SpringBean
通过Component、Repository、Service、Controller等注解定义bean在启动类上加上ComponentScan注解在项目启动时ComponentScan扫描指定路径下的包包内含有Component、Repository、Service、Controller等注解的类会被注册成Bean放到BeanDefinitionMap中并创建实例到单例池。
Data
NoArgsConstructor
AllArgsConstructor
Component
public class User {public String name;
} 这里使用了xml配置了componentScan到了SpringBoot就完全使用注解ComponentScan ?xml version1.0 encodingUTF-8?beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd!--指定要扫描的包这个包下的注解就会生效--context:component-scan base-packagecom.kuang.pojo/!--开启注解的支持 --context:annotation-config//beans1.2 装配Spring Bean的四种常用方式
1.2.1 手动装配 XML文件
package com.javastudyway.pojo;
public class Cat {public void shout(){System.out.println(我是猫);}
}package com.javastudyway.pojo;
publicclass Dog {public void shout(){System.out.println(我是狗);}
}Data
NoArgsConstructor
AllArgsConstructor
public class Person {/* 人有猫和狗 */private Cat cat;private Dog dog;private String name;
}bean idcat classcom.javastudyway.pojo.Cat/bean iddog classcom.javastudyway.pojo.Dog/bean idperson classcom.javastudyway.pojo.Personproperty namename valueJava学习之道/property namecat refcat/property namedog refdog//bean1.2.2 自动装配 XML文件 bean idcat classcom.javastudyway.pojo.Cat/bean iddog classcom.javastudyway.pojo.Dog/!--byType--bean idperson classcom.javastudyway.pojo.Person autowirebyTypeproperty namename valueJava学习之道//bean!--byName--bean idperson classcom.javastudyway.pojo.Person autowirebyNameproperty namename valueJava学习之道//bean1.2.3 手动装配 JavaConfig文件
Configuration//标明配置
public class PeopleConfig {Beanpublic Cat catBean(){return new Cat();}Beanpublic CDPlayer dogBean(){return new Dog();}Beanpublic People peopleBean(){return new People(catBean(),dogBean(),Java学习之道);}
}1.2.4 自动装配 注解
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd!-- 开启注解支持 --context:annotation-config/bean idcat classcom.javastudyway.pojo.Cat/bean iddog classcom.javastudyway.pojo.Dog/bean idperson classcom.javastudyway.pojo.Person//beanspublic class Pepole {Autowiredprivate Cat cat;Autowiredprivate Dog dog;private String name;2. Spring Bean注册到容器中
以UserService讲解Bean注册到容器中的过程。
mapper
public class UserService{Autowiredprivate OrderService orderService;public void test(){System.out.println(orderService);}
}2.1 实例化生成普通对象
2.1.1 通过反射机制获取构造器通过构造器创建普通对象
创建Bean过程中推断所使用的构造器方法 如果没有重写构造方法那么创建Bean对象就会用无参构造方法如果重写了一个有参构造方法那么创建Bean对象就会用该有参构造方法如果重写了两个有参构造方法那么创建Bean对象不知道用哪个有参构造方法就会去寻找无参构造方法如果没有无参构造方法就报错。如果存在无参构造方法就执行无参构造方法。可以通过Autowired指定使用该构造方法即使存在无参构造器也要使用这个有参构造器 谁向有参构造器public UserService(OrderService orderService)中传入参数 当我们创建Bean对象userService时需要用到有参构造方法Spring就会在单例池中找到OrderService对象并注入到构造方法的参数orderService 如何在单例池中找到自己想要的实例呢 如果通过类型OrderService找出beanName唯一那就直接将Bean对象注入orderService。如果通过参数的类OrderService找出beanName不唯一那就通过参数名orderService找出唯一的beanName然后将Bean对象注入orderService参数如果这样都找不到那就报错 2.1.2 属性注入
2.1.3 初始化
这里通过执行invoke方法将普通对象初始化
2.1.4 初始化后生成代理对象
这里就是我们常说的AOP如果这里进行了AOP切面编程那么就会生成代理对象
创建普通对象UserService
Component
public class UserService{Autowiredprivate OrderService orderService;public void test(){System.out.println(orderService);}}创建代理对象UserServiceProxy对test方法进行切面编程
Aspect
Component
public class UserServiceProxy{Before(execution(public void com.zhouyu.service.UserService.test()))public void zhouyuBefore(JoinPoint joinPoint){System.out.println(zhouyuBefore);}
}现在来思考一个问题在普通对象userService的属性orderService有Autowired进行依赖注入那么orderService是有值的。但是在初始化后进行了AOP生成了代理对象userServiceProxyuserServiceProxy的属性orderService并没有注入依赖是null这就来问题了。 其实第3点的伪代码应该改成如下这样就解决了null值得问题了下面说说为什么。试想一下生成普通对象userService并为普通对象userService的属性orderService依赖注入那么为什么生成代理对象userServiceProxy不为代理对象userServiceProxy的属性orderService进行依赖注入呢Spring认为是没必要的就像下面的伪代码一样除了执行AOP切面编程的代码之外还是用回普通对象userService属性和方法所以一句话说完UserServiceProxy代理对象做Bean对象除了切面编程Before会执行代理对象其他的方法和属性可以认为是在执行普通对象 Aspect
Component
public class UserServiceProxy{Autowiredprivate UserService target;Before(execution(public void com.zhouyu.service.UserService.test()))public void zhouyuBefore(JoinPoint joinPoint){System.out.println(zhouyuBefore);}
}2.1.5 注册销毁
实现了销毁接口DisposableBean在registerDisposableBean方法注册指定的Bean在销毁时可以直接执行destroy方法销毁Bean
2.1.6 将普通对象或者代理对象加入单例池中
3. Spring注解开发
3.1 使用注解开发前需要做的配置
3.1.1 使用注解开发必须要保证导入aop包 3.1.2 使用注解需要导入context约束、增加注解的支持 ?xml version1.0 encodingUTF-8?beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd!--开启注解的支持 --context:annotation-config//beans3.2 了解常用的注解
3.2.1 Component、Mapper、Service、Controller
3.2.2 Bean
用于JavaConfig配置类充当xml的bean标签
3.2.3 ComponentScan 通过属性basePackages或basePackageClasses来指定要进行扫描的package如果未指定package则默认扫描当前ComponentScan所修饰的类所在的package 3.2.4 Import
提供了一种显式地从其他地方加载配置类的方式这里的其他地方一般是指第三方jar
//1. 创建普通Java类public class ConfigA{Beanpublic A a(){public new A();}}public class A{}//2. 创建一个配置类直接将刚才创建的ConfigA导入ConfigurationImport(ConfigA.class)public class ConfigB{}//3. 测试并运行public static void main(String[] args){ApplicationContext ctx new AnnotationCconfigApplicationContext(ConfigB.class);//现在Bean ConfigA和A都在IOC容器中是可用的ConfigA ca ctx.getBean(ConfigA.class);A a ctx.getBean(A.class);System.out.println(ca.getClass.getSimpleName());System.out,println(a.getClass.getSimpleName());}
结果ConfigA、A3.2.5 Autowired和Qualifier
public class Pepole {private String name;
//1. 通过名字装配AutowiredQualifier(books1)private Books books;
//2. 通过类型装配Autowiredprivate Hobbies hobbies;
}3.2.6 Resource
// Resource指定按type自动装配Resource(type Books.class)private Books books;// Resource指定按name自动装配Resource(name books)private Books books;3.2.7 Value
基于配置文件application.yml
!--application.yml--
server:port: 9090tools: car,train,airplaneValue(${server.port})private String port;Value(${server.tools})private String[] tools基于非配置文件 // 直接将字符串赋值给 str 属性Value(hello world)private String str;// 注入系统变量Value(#{systemProperties[os.name]})private String osName; // 结果Windows 10// 使用在setter方法上Value(Windows)public void setName(String name){this.name name;}4. Spring事务
4.1 本质与原理讲解Spring事务是基于AOP实现的AOP是基于继承原理的。
1. Spring事务是基于AOP实现的
现在对UserService的test方法开启MySQL事务
public class UserService{AutowiredOrderService ordserService;Transactional //回滚——Spring事务public void test(){jdbcTemplate.execute(insert into t1 values(1,1,1,1,1));throw new NullPointerException();}
}Transaction修饰test方法对应的伪代码
public class UserServiceProxy extends UserService{UserService target;//不难看出来1.2.3.4.6都是对test做一个切面由UserServiceProxy代理对象执行//test方法由普通对象执行public void test(){1. 事务逻辑2. 开启事务3. 事务管理器去创建数据库连接conn并放入了ThreadLocal4. conn.autocommit false5. target.test(); //UserService普通对象.test() jdbcTemplate conn sql语句6. SQL没问题就conn.commit()否则就conn.rollback();}
}autocommit true对应的功能 如果数据库由jdbcTemplate连接autocommit默认为true则执行完SQL语句之后就会自动提交如果数据库由Spring连接那么Spring就会把autocommit改成false则执行完SQL语句之后还不会自动提交所以数据库创建必须由Spring来进行但是如果由Spring创建数据库那么Spring一启动就要连接数据库万一我们不用数据库呢不用就不用呗哈哈哈哈 2. AOP是基于继承原理的
public class UserService{Transactionprivate void test(){System.out.println(测试数据库回滚事务);}
}执行结果报错分析 事务的实质是AOPAOP的实质是继承所以事务的实质是继承父类private修饰的方法子类无法访问重写所以父类private修饰的方法无法进行AOP也无法进行事务那么Transaction就会报错 4.2 事务失效场景
什么是事务失效呢其实就是事务不会正常工作可以发生如下情况 事务没有启动事务启动了但是无法回滚或者回滚了很多… 4.2.1 访问权限问题private
把某些方法或者变量定义为private对其开启事务时会导致事务失效。因为事务基于继承private修饰的父类方法和变量子类无法继承。
4.2.2 final修饰
如果某个方法用 final 修饰了那么在它的代理类中就无法重写该方法所以无法添加事务功能
4.2.3 未被Spring管理
如果有一天你匆匆忙忙地开发了一个 Service 类但忘了加 Service 注解比如
//Service
public class UserService {Transactionalpublic void add(UserModel userModel) {saveData(userModel);updateData(userModel);}
}从上面的例子我们可以看到 UserService 类没有加Service注解那么该类不会交给 spring 管理所以它的 add 方法也不会生成事务。
4.2.4 表不支持事务
众所周知在 mysql5 之前默认的数据库引擎是myisam。myisam 好用但有个很致命的问题是不支持事务。如果只是单表操作还好不会出现太大的问题。但如果需要跨多张表操作由于其不支持事务数据极有可能会出现不完整的情况。此外myisam 还不支持行锁和外键。所以在实际业务场景中myisam 使用的并不多。在 mysql5 以后myisam 已经逐渐退出了历史的舞台取而代之的是 innodb。
4.2.5 未开启事务
如果你使用的是 springboot 项目那么你很幸运。因为 springboot 通过DataSourceTransactionManagerAutoConfiguration类已经默默地帮你开启了事务。
你所要做的事情很简单只需要配置spring.datasource相关参数即可。
但如果你使用的还是传统的 spring 项目则需要在 applicationContext.xml 文件中手动配置事务相关参数。如果忘了配置事务肯定是不会生效的。
具体配置信息如下
!-- 配置事务管理器 --
bean classorg.springframework.jdbc.datasource.DataSourceTransactionManager idtransactionManager property namedataSource refdataSource/property
/bean
tx:advice idadvice transaction-managertransactionManager tx:attributes tx:method name* propagationREQUIRED//tx:attributes
/tx:advice
!-- 用切点把事务切进去 --
aop:config aop:pointcut expressionexecution(* com.susan.*.*(..)) idpointcut/ aop:advisor advice-refadvice pointcut-refpointcut/
/aop:config 4.2.6 方法内部调用
来看两个示例
Service
public class OrderServiceImpl implements OrderService {public void update(Order order) {updateOrder(order);}Transactionalpublic void updateOrder(Order order) {// update order}}Service
public class OrderServiceImpl implements OrderService {Transactionalpublic void update(Order order) {updateOrder(order);}Transactional(propagation Propagation.REQUIRES_NEW)public void updateOrder(Order order) {// update order}}上面两个例子的updateOrder(Order order) 都不会生成事务因为它们发生了自身调用就调该类自己的方法而没有经过 Spring 的代理类默认只有在外部调用事务才会生效这也是老生常谈的经典问题了。
解决办法
Service
public class ServiceA {Autowiredprivate ServiceB serviceB;Transactionalpublic void update(Order order) {updateOrder(order);}
}
Service
public class ServiceB {Transactional(propagation Propagation.REQUIRES_NEW)public void updateOrder(Order order) {// update order}
}4.2.7 错误的传播特性
我们在使用Transactional注解时是可以指定propagation参数的该参数的作用是指定事务的传播特性spring 目前支持 7 种传播特性 REQUIRED 如果当前上下文中存在事务则加入该事务如果不存在事务则创建一个事务这是默认的传播属性值。SUPPORTS 如果当前上下文中存在事务则支持事务加入事务如果不存在事务则使用非事务的方式执行。MANDATORY 当前上下文中必须存在事务否则抛出异常。REQUIRES_NEW 每次都会新建一个事务并且同时将上下文中的事务挂起执行当前新建事务完成以后上下文事务恢复再执行。NOT_SUPPORTED 如果当前上下文中存在事务则挂起当前事务然后新的方法在没有事务的环境中执行。NEVER 如果当前上下文中存在事务则抛出异常否则在无事务环境上执行代码。NESTED 如果当前上下文中存在事务则嵌套事务执行如果不存在事务则新建事务。 目前只有这三种传播特性才会创建新事务REQUIREDREQUIRES_NEWNESTED。
如果我们在手动设置 propagation 参数的时候把传播特性设置错了比如
Service
public class UserService {Transactional(propagation Propagation.NEVER)public void add(UserModel userModel) {saveData(userModel);updateData(userModel);}
}我们可以看到 add 方法的事务传播特性定义成了 Propagation.NEVER这种类型的传播特性不支持事务如果有事务则会抛异常。
4.2.8 自己吞了异常
Slf4j
Service
public class UserService {Transactionalpublic void add(UserModel userModel) {try {saveData(userModel);updateData(userModel);} catch (Exception e) {log.error(e.getMessage(), e);}}
}这种情况下 spring 事务当然不会回滚因为开发者自己捕获catch了异常又没有手动抛出throw换句话说就是把异常吞掉了。
如果想要 spring 事务能够正常回滚必须抛出它能够处理的异常。如果没有抛异常则 spring 认为程序是正常的。
4.2.9 手动抛了别的异常
因为 spring 事务默认情况下只会回滚RuntimeException运行时异常和Error错误对于普通的 Exception非运行时异常它不会回滚。
Slf4j
Service
public class UserService {Transactionalpublic void add(UserModel userModel) throws Exception {try {saveData(userModel);updateData(userModel);} catch (Exception e) {log.error(e.getMessage(), e);throw new Exception(e);}}
}4.2.10 事务嵌套回滚多了
public class UserService {Autowiredprivate UserMapper userMapper;Autowiredprivate RoleService roleService;Transactionalpublic void add(UserModel userModel) throws Exception {userMapper.insertUser(userModel);roleService.doOtherThing();}
}Service
public class RoleService {Transactional(propagation Propagation.NESTED)public void doOtherThing() {System.out.println(保存role表数据);}
}这种情况使用了嵌套的内部事务原本是希望调用 roleService.doOtherThing 方法时如果出现了异常只回滚 doOtherThing 方法里的内容不回滚 userMapper.insertUser 里的内容即回滚保存点。但事实是insertUser 也回滚了。
why?
因为 doOtherThing 方法出现了异常没有手动捕获会继续往上抛到外层 add 方法的代理方法中捕获了异常。所以这种情况是直接回滚了整个事务不只回滚单个保存点。
怎么样才能只回滚保存点呢可以将内部嵌套事务放在 try/catch 中并且不继续往上抛异常。这样就能保证如果内部嵌套事务中出现异常只回滚内部事务而不影响外部事务。
Slf4j
Service
public class UserService {Autowiredprivate UserMapper userMapper;Autowiredprivate RoleService roleService;Transactionalpublic void add(UserModel userModel) throws Exception {userMapper.insertUser(userModel);try {roleService.doOtherThing();} catch (Exception e) {log.error(e.getMessage(), e);}}
}4.2.11 大事务
在使用 spring 事务时有个让人非常头疼的问题就是大事务问题。
通常情况下我们会在方法上加Transactional注解添加事务功能比如
Service
public class UserService {Autowired private RoleService roleService;Transactionalpublic void add(UserModel userModel) throws Exception {query1();query2();query3();roleService.save(userModel);update(userModel);}
}但Transactional注解如果被加到方法上有个缺点就是整个方法都包含在事务当中了。 上面的这个例子中在 UserService 类中其实只有这两行才需要事务
roleService.save(userModel);
update(userModel);现在的这种写法会导致所有的 query 方法也被包含在同一个事务当中。
如果 query 方法非常多调用层级很深而且有部分查询方法比较耗时的话会造成整个事务非常耗时而从造成大事务问题。
4.3 编程式事务
上面聊的这些内容都是基于Transactional注解的主要说的是它的事务问题我们把这种事务叫做声明式事务。
其实spring 还提供了另外一种创建事务的方式即通过手动编写代码实现的事务我们把这种事务叫做编程式事务。例如 Autowiredprivate TransactionTemplate transactionTemplate;...public void save(final User user) {queryData1();queryData2();transactionTemplate.execute((status) {addData1();updateData2();return Boolean.TRUE;})}在 spring 中为了支持编程式事务专门提供了一个类TransactionTemplate在它的 execute 方法中就实现了事务的功能。
相较于Transactional注解声明式事务我更建议大家使用基于TransactionTemplate的编程式事务。主要原因如下
避免由于 spring aop 问题导致事务失效的问题。能够更小粒度地控制事务的范围更直观。 建议在项目中少使用 Transactional 注解开启事务。但并不是说一定不能用它如果项目中有些业务逻辑比较简单而且不经常变动使用 Transactional 注解开启事务也无妨因为它更简单开发效率更高但是千万要小心事务失效的问题。
文章转载自: http://www.morning.zhengdaotang.cn.gov.cn.zhengdaotang.cn http://www.morning.fkmrj.cn.gov.cn.fkmrj.cn http://www.morning.xknmn.cn.gov.cn.xknmn.cn http://www.morning.rqxmz.cn.gov.cn.rqxmz.cn http://www.morning.skmpj.cn.gov.cn.skmpj.cn http://www.morning.ppbqz.cn.gov.cn.ppbqz.cn http://www.morning.nhrkc.cn.gov.cn.nhrkc.cn http://www.morning.srgsb.cn.gov.cn.srgsb.cn http://www.morning.lkbyj.cn.gov.cn.lkbyj.cn http://www.morning.nkpml.cn.gov.cn.nkpml.cn http://www.morning.ytfr.cn.gov.cn.ytfr.cn http://www.morning.blfll.cn.gov.cn.blfll.cn http://www.morning.ltpzr.cn.gov.cn.ltpzr.cn http://www.morning.lffrh.cn.gov.cn.lffrh.cn http://www.morning.qttg.cn.gov.cn.qttg.cn http://www.morning.diuchai.com.gov.cn.diuchai.com http://www.morning.mnlk.cn.gov.cn.mnlk.cn http://www.morning.kjfqf.cn.gov.cn.kjfqf.cn http://www.morning.rjyd.cn.gov.cn.rjyd.cn http://www.morning.jrksk.cn.gov.cn.jrksk.cn http://www.morning.bhjyh.cn.gov.cn.bhjyh.cn http://www.morning.xskbr.cn.gov.cn.xskbr.cn http://www.morning.paxkhqq.cn.gov.cn.paxkhqq.cn http://www.morning.txzmy.cn.gov.cn.txzmy.cn http://www.morning.hrtwt.cn.gov.cn.hrtwt.cn http://www.morning.zfrs.cn.gov.cn.zfrs.cn http://www.morning.jbtwq.cn.gov.cn.jbtwq.cn http://www.morning.ntwxt.cn.gov.cn.ntwxt.cn http://www.morning.lrskd.cn.gov.cn.lrskd.cn http://www.morning.nbsbn.cn.gov.cn.nbsbn.cn http://www.morning.jfbrt.cn.gov.cn.jfbrt.cn http://www.morning.ydnx.cn.gov.cn.ydnx.cn http://www.morning.dqpnd.cn.gov.cn.dqpnd.cn http://www.morning.kflpf.cn.gov.cn.kflpf.cn http://www.morning.ldfcb.cn.gov.cn.ldfcb.cn http://www.morning.lzjxn.cn.gov.cn.lzjxn.cn http://www.morning.lqgtx.cn.gov.cn.lqgtx.cn http://www.morning.jrhmh.cn.gov.cn.jrhmh.cn http://www.morning.hwsgk.cn.gov.cn.hwsgk.cn http://www.morning.zrmxp.cn.gov.cn.zrmxp.cn http://www.morning.spxk.cn.gov.cn.spxk.cn http://www.morning.nmnhs.cn.gov.cn.nmnhs.cn http://www.morning.zfzgp.cn.gov.cn.zfzgp.cn http://www.morning.rhwty.cn.gov.cn.rhwty.cn http://www.morning.gnghp.cn.gov.cn.gnghp.cn http://www.morning.pqqxc.cn.gov.cn.pqqxc.cn http://www.morning.tpfny.cn.gov.cn.tpfny.cn http://www.morning.gmztd.cn.gov.cn.gmztd.cn http://www.morning.hsksm.cn.gov.cn.hsksm.cn http://www.morning.xdfkrd.cn.gov.cn.xdfkrd.cn http://www.morning.tqsnd.cn.gov.cn.tqsnd.cn http://www.morning.qdrrh.cn.gov.cn.qdrrh.cn http://www.morning.mhnxs.cn.gov.cn.mhnxs.cn http://www.morning.lzrpy.cn.gov.cn.lzrpy.cn http://www.morning.ztqj.cn.gov.cn.ztqj.cn http://www.morning.rkjb.cn.gov.cn.rkjb.cn http://www.morning.joinyun.com.gov.cn.joinyun.com http://www.morning.qsbcg.cn.gov.cn.qsbcg.cn http://www.morning.mqdr.cn.gov.cn.mqdr.cn http://www.morning.xglgm.cn.gov.cn.xglgm.cn http://www.morning.tqjks.cn.gov.cn.tqjks.cn http://www.morning.rnzwh.cn.gov.cn.rnzwh.cn http://www.morning.sjwws.cn.gov.cn.sjwws.cn http://www.morning.cwnqd.cn.gov.cn.cwnqd.cn http://www.morning.zxxys.cn.gov.cn.zxxys.cn http://www.morning.gypcr.cn.gov.cn.gypcr.cn http://www.morning.snbrs.cn.gov.cn.snbrs.cn http://www.morning.crkmm.cn.gov.cn.crkmm.cn http://www.morning.guangda11.cn.gov.cn.guangda11.cn http://www.morning.xqbbc.cn.gov.cn.xqbbc.cn http://www.morning.pjfmq.cn.gov.cn.pjfmq.cn http://www.morning.ymbqr.cn.gov.cn.ymbqr.cn http://www.morning.qgjxy.cn.gov.cn.qgjxy.cn http://www.morning.mzjbz.cn.gov.cn.mzjbz.cn http://www.morning.rhwty.cn.gov.cn.rhwty.cn http://www.morning.yesidu.com.gov.cn.yesidu.com http://www.morning.llfwg.cn.gov.cn.llfwg.cn http://www.morning.rythy.cn.gov.cn.rythy.cn http://www.morning.dphmj.cn.gov.cn.dphmj.cn http://www.morning.jljwk.cn.gov.cn.jljwk.cn