Spring FramkWrok
1.介绍
- Spring是一个IOC(DI)和AOP容器框架
- 轻量级:Spring是非侵入性的 开发不依赖Spring的API
- 包含:
- 依赖注入 (DI)
- 面向切面编程 (AOP)
2.spring 的helloworld
-
applicationContext.xml中配置
-
Main方法中
// HelloWorld helloWorld = new HelloWorld(); // helloWorld.setName("JIAT"); //以上可以由spring完成 //1.创建Spring的IOC对象:会对xml中设置的bean创建对象调用构造方法,并且对property标签中的属性赋值 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从IOC容器中获取Bean实例 // HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloworld"); //使用id获取 HelloWorld helloWorld = ctx.getBean(HelloWorld.class); //使用类型获取(同类型的bean无法区分) //3.调用 helloWorld.hello();
3.javaBean的注入
IOC & DI (使用的是工厂模式)
IOC: 反转资源获取的方向 原方向:组件向容器请求资源,容器返回资源;反方向:容器主动的将资源给到组件,组件要做的是选择一种合适的方式来接受资源
DI: IOC的另一种表述方式,组件以一些定义好的方式,接受来自如容器的资源注入
1.工厂方法注入bean
- IOC容器的初始化,使用beanfactory的子接口ApplicationContext,ApplicationContext有两个主要的实现类ClassPathXmlApplicationContext(从类路径下加载配置文件)和FileSystemXmlApplicationContext(从文件系统下加载配置文件)
- 从IOC容器中获取Bean实例
- HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloworld"); //使用id获取
- HelloWorld helloWorld = ctx.getBean(HelloWorld.class); //使用类型获取(同类型的bean无法区分)
2.依赖注入方式
1.在xml中bean标签属性
- Class: bean的全类名,通过反射的方式在IOC容器中创建bean,所以要求bean中必须有无参构造器
- Id: 标识容器中的bean,id唯一
2.注入方式
属性注入和构造器注入常用,工厂方法注入很少且不推荐
- 属性注入:利用setter方法注入bean属性值或者依赖的对象。
使用 例子如上 (需要无参构造器)
- 构造方法注入:通过构造方法注入,保证bean在实例化之后就可以使用,在 中声明属性,没有name属性(该方法无需无参构造器)
//price
//对应maxSpeed
public CAR(String brand, String corp, double price) {
this.brand = brand;
this.corp = corp;
this.price = price;
}
public CAR(String brand, String corp, int maxSpeed) {
this.brand = brand;
this.corp = corp;
this.maxSpeed = maxSpeed;
}
细节:
字面值:可以直接使用value或者constructor-arg标签中子标签value的方式,若字面值中包括特殊字符,可以使用把字面值包裹起来
]]>
-
引用其他的bean:
在property中使用ref直接引用其他bean的id
结果如下
Person{name='Tom', age=24, car=CAR{brand='Baoma', corp=' ', price=0.0, maxSpeed=240}}
-
创建内部bean(无法被其他的外部bean引用)
-
注入参数详解:null值和级联属性
可以使用专用的 为属性赋空值
级联属性赋值:在对应的类中,要有该属性的set方法
//需要有这一句先初始化,否则异常 -
集合属性
(list和数组)
-
配置Properties,每个 标签必须定义key属性
root
123
jdbc:mysql:///test
com.mysql.jdbc.Driver
-
单独配置集合bean,以可以被其他bean引用、
-
使用p命名空间(需要声明)
xmlns:p="http://www.springframework.org/schema/p"
-
使用外部属性文件
Properties
user =root password = driverclass = com.mysql.jdbc.Driver jdbcurl = jdbc:mysql:///test
导入文件属性
获取文件属性用${}
3.自动装配
IOC容器可以自动装配bean,需要做的就是在bean的autowire属性里指定自动装配的模式
- ByType:根据类型自动装配,如果容器中有多个与目标bean类型一致的,将无法判定,不能执行自动装配
- ByName:根据名称自动装配,不许将目标bean的名称和属性名设置的完全相同
- Constructor:通过构造器自动装配:当bean中存在多个构造器时很复杂
//adderss和car的beanid都必须与person类中的属性名相同 没有匹配的赋空值
public class Person {
private String name;
private Address address;
private Car car;
缺点:
自动装配会配置bean中的所有属性,不够灵活
4.java bean
1.bean之间的关系
继承
定义了abstract的bean不能被实例化,只能作为模板被继承
若某一个bean没有指定class属性,则该bean必须是一个抽象bean
依赖
依赖多个时,通过逗号 空格的方式配置bean名称
2.Bean的作用域
默认为单例: scope="singleton"
public static void main(String[] args) {
//单例创建
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml");
//原型创建
Car car = (Car) ctx.getBean("car");
Car car2 = (Car) ctx.getBean("car");
System.out.println(car==car2);
}
5.SPEL
1.介绍
Spring表达式语言:是一个支持运行时查询和操作对象图的强大的表达式语言
语法类似EL:SpEL使用#{}作为定界符,所有在大括号里的字符都被认为是SpEL
2. 用途:
- 通过Bean的id对bean进行引用
- 调用方法以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
3.应用
-
引用其他对象
-
引用其他对象的属性
-
支持算数运算符
字符串+连接
-
逻辑运算符:and,or,not,| , !
-
比较运算符(< , > , <= , >= , == , lt , gt , eq , le , ge)
If-else:表达式 ? ‘’ : ‘’
-
调用静态方法或静态属性
6.IOC容器管理
1.IOC容器可以管理Bean的生命周期
- Init和destory为类中自己定义的方法,作为初始化方法和关闭
- 当为单例时,容器创建就调用init方法,容器关闭即 close()时,执行destroy
- 当为原型时,只有实例化时才会调用init,每次实例化都会执行一次,容器关闭时也不会执行destroy
2.创建bean后置处理器(不需要指定id)
Bean后置处理器允许在调用初始化方法前后对bean进行额外的处理,对IOC容器中的所有bean实例逐一进行处理,而非单一实例
配置
继承BeanPostProcessor(bean为bean对象,beanName为bean配置的id)
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("After init...."+ bean+","+beanName);
if ("car".equals(beanName)){ //过滤bean
Car car = new Car();
car.setBrand("BaoMa");
return car;
}
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Before init..." + bean+","+beanName);
return bean;
}
}
7.开发中配置bean的几种方式
1.通过工厂方法配置bean
1.静态工厂
public class StaticCarFactory {
//直接调用某一个类的静态方法,就可以返回bean的实例
private static Map cars = new HashMap();
static {
cars.put("audi" , new Car("audi",300000));
cars.put("ford" , new Car("ford",400000));
}
//静态工厂方法
public static Car getCar(String name){
return cars.get(name);
}
}
//静态方法参数输入
2.实例工厂
//实例工厂 的 方法,即先创建工厂本身再调用工厂的实例方法
public class InstanceCarFactory {
private Map cars = null;
public InstanceCarFactory() {
cars = new HashMap();
cars.put("audi",new Car("audi",300000));
cars.put("ford",new Car("ford",400000));
}
public Car getCar(String brand){ //静态方法
return cars.get(brand);
}
}
2.通过FactoryBean
//自定义的FactoryBean需要实现FactoryBean接口
public class CarFactoryBean implements FactoryBean {
private String brand;
public void setBrand(String brand) {
this.brand = brand;
}
//返回bean的对象
@Override
public Car getObject() throws Exception {
return new Car(brand,500000);
}
//返回bean的类型
@Override
public Class> getObjectType() {
return Car.class;
}
//返回是否为单例
@Override
public boolean isSingleton() {
return true;
}
}
3.基于注解的方式
1.Spring能从classpath下自动扫描,侦测和实例化具有特定注解的组件。
特定组件包括:
-
@Component:基本注解,表示了一个受Spring管理的组件
-
@Respository:标识持久层组件
-
@Service:标识服务层(业务层)组件
-
@Controller:标识表现层组件
@Service //注解 public class UserService { public void add(){ System.out.println("UserService add..."); } }
对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写,也可以在注解中通过value属性值标识组件名称
@Repository("userRepository") //自定义名字
2.当在组件类上使用了特定注解之后,还需要在Spring的配置文件中声明context:component-scan:
3.基于注解来配置Bean的属性
context:component-scan元素会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired 和 @Resource 、@Inject 注解的属性
@Autowired 注解自动装配具有兼容类型的单个bean属性
普通的字段以及一切具有参数的方法都可以应用@Autowired注解
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
@Autowired
private UserService userService;
默认情况下,所有使用该注解的属性都需要被设置,当Spring找不到匹配的bean装配属性时,会抛出异常,若某一属性允许不被设置,可以设置注解的required属性为false
@Autowired(required = false)
private UserService userService;
当有多个类型相同的bean时,该注解会先找和注解中需要的bean名称相同的bean,若没有名称相同的bean且有多个相同类型,则会报错
-
装配的时候定义相同名字
-
利用@Qualifier的注解指定装配哪个bean:该注解还可以加到入参前面
@Autowired
@Qualifier("userRepositoryImpl")
private UserRepository userRepository;
@Resource 、@Inject与@Autowired相类似
@Resource注解要求提供一个bean名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为bean的名称
@Inject 注解按类型匹配注入的bean,但没有required属性
4.Spring 4.x泛型依赖注入:
在泛型父类中建立关系,在子类中也有这个关系
public class BaseService {
@Autowired //父类中建立联系,其子类无需再进行装配
protected BaseRespository respository;
public void add(){
System.out.println("add...");
System.out.println(respository);
}
}
8.在web中的应用
Spring在web应用中使用需要额外加入jar包:
Spring-web 和Spring-webmvc
创建IOC容器:(核心思路)
-
非WEB应用在main方法中直接创建
-
实际上,Spring配置文件的名字和位置也是可以配置的!将其配置到当前web应用的初始化参数中
configLocation
applicationContext.xml
Listeners.SpringServletContextListener
-
应该在web应用被服务器加载时就创建IOC容器:----监听器ServletContextListener init方法
-
在web应用的其他组件中如何来访问IOC容器
创建IOC容器后将其放入ServletContext(即application域中)的一个属性中
public void contextInitialized(ServletContextEvent sce) {
//获取初始化在web配置文件中的Spring配置文件的名称和位置
ServletContext servletContext = sce.getServletContext();
String config = servletContext.getInitParameter("configLocation");
//创建IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
//放入ServletContext中
servletContext.setAttribute("ApplicationContext",ctx);
}
调用:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.从application域对象中得到IOC容器的引用
ServletContext servletContext = getServletContext();
ApplicationContext ctx = (ApplicationContext) servletContext.getAttribute("ApplicationContext");
//2.从IOC容器中得到需要的bean
Person person= (Person) ctx.getBean("person");
person.hello();
}
使用Spring封装好的接口来获取IOC
新建applicationContext.xml文件
在web配置文件中一下配置:org.springframework.web.context.ContextLoaderListener为Spring提供的API,已经完成了以上监听器的核心步骤,只需要直接从ServletContext中获取就好
contextConfigLocation
classpath:applicationContext.xml
org.springframework.web.context.ContextLoaderListener
获取IOC:使用WebApplicationContextUtils. getWebApplicationContext(application)获取
//从application中获取IOC实例
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(application);
//从IOC容器中得到bean
Person person = ctx.getBean(Person.class);
//使用bean
person.hello();
9.Spring AOP切面编程
1.介绍
应用:
可以解决由于非业务需求(日志和验证等 )加入而引起的代码混乱
可以解决修改需求时,需要修改多个模块中相同代码,即解决代码分散的问题
2.实现
使用动态代理:使用一个代理将对象包装起来
业务代码接口-------(实现类)----------à 业务代码(类加载器)
定义一个代理,传入代理的对象(即业务代码) 完成一个返回上述类的方法
//业务代码,即需要代理的类加载器
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i+j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i-j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i*j;
return result;
}
@Override
public int div(int i, int j) {
int result = i/j;
return result;
}
}
//业务接口
public interface ArithmeticCalculator {
int add(int i ,int j);
int sub(int i ,int j);
int mul(int i ,int j);
int div(int i ,int j);
}
//代理器
public class ArithmeticCalculatorLoggingProxy {
//要代理的对象
private ArithmeticCalculator target;
public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
this.target = target;
}
public ArithmeticCalculator getLoggingProxy(){
ArithmeticCalculator proxy = null;
//代理对象由哪一个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class[] interfaces = new Class[]{ArithmeticCalculator.class};
//当调用代理对象其中的方法是,该执行的代码
InvocationHandler h = new InvocationHandler() {
//o : 正在返回的代理对象,一般情况下,在invoke方法中的不使用该对象
//method:正在被调用的方法
//args:调用方法时传入的参数
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
String methodName = method.getName();
System.out.println("The method "+methodName+" begins with "+ Arrays.asList(objects));
int result = (int) method.invoke(target,objects);
System.out.println("The method "+methodName+" ends with "+result);
return result;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces,h);
return proxy;
}
}
调用:
ArithmeticCalculator target = new ArithmeticCalculatorImpl();
ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy(); //proxy为代理的加载器
3.AOP的概念描述
- AOP的主要编程对象是切面,而切面模块化横切关注点,在应用AOP编程时,需要定义公共功能,但是可以明确定义这个功能在哪里,以什么方式应用,而不必修改受影响的类,如此横切关注点就模块化到特殊的对象(切面)里
- 连接点:程序执行的某个特定位置,是个物理存在,即某个方法执行前,执行后,或抛出异常后等的点。由两个信息确认,一个是方法表示的程序执行点,一个是相对点的方位;即add()方法的连接点:执行点为add(),方位为add()方法执行前(后)的位置(一个类多个)
- 切点:AOP通过切点定位到特定的连接点,切点通过org.springframework.aop.Pointcut描述
4.基于注解的方式配置AOP
1.AspectJ
AspectJ:最完整最流行的AOP框架
在Spring2.0以上的版本中,可以使用基于AspectJ注解或基于XML配置的AOP
要在SpringIOC容器中启用AspectJ注解支持,只要在Bean配置文件中定义一个空的XML元素aop:aspectj-autoproxy
2.定义切面类
带有@Aspect和@Component注解的类
通知有5个:Execution表达式@Before("execution(public int AOPImpl.ArithmeticCalculator.*(int ,int))")
修饰符 类型 包名 类名 方法名 (可以用*号来代替任意修饰符任意类型任意方法任意类,任意参数用..)
-
@Before 前置通知,方法执行前执行
//将这个类声明为切面: //1.将该类放入到IOC容器中 //2.再声明为一个切面 @Aspect @Component public class LoggingAspect { //日志切面 //声明该方法是个前置通知:在目标方法开始之前执行 @Before("execution(public int AOPImpl.ArithmeticCalculator.*(int ,int))") public void beforeMethod(JoinPoint joinPoint){ //JoinPoint 连接点,可以获取目标方法信息 String methodName = joinPoint.getSignature().getName(); //获取方法名 List
-
@After 后置通知,方法执行后执行
//后置通知,无论是否异常都可以执行,无法访问目标方法执行的结果 @After("execution(public int AOPImpl.ArithmeticCalculator.*(int,int ))") public void afterMethod(JoinPoint joinPoint){ String methodName =joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " ends."); }
-
@AfterReturning 返回通知,在方法返回结果之后执行
/返回通知可以访问到方法的返回值,出现异常不会返回,定义一个returning @AfterReturning(value = "execution(public int AOPImpl.ArithmeticCalculator.*(..))",returning = "result") public void afterReturning(JoinPoint joinPoint,Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " ends with "+result); }
-
@AfterThrowing 异常通知,在方法抛出异常之后执行
//在目标方法出现异常时,会执行的代码,而且可以访问到一场对象,可以指定在出现特定异常时执行通知代码 @AfterThrowing(value = "execution(public int AOPImpl.ArithmeticCalculator.*(..))",throwing = "ex") public void afterThrowing(JoinPoint joinPoint,Exception ex){ //定义ex的类型可以指定特定异常 String methodName = joinPoint.getSignature().getName(); System.out.println("The method "+methodName+ " occurs excetion "+ex); }
-
@Around 环绕通知,围绕着方法执行
//环绕通知需要携带ProceedingJoinPoint类型的参数 //环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。 //且环绕通知必须有返回值,返回值即为目标方法的返回值 @Around("execution(public int AOPImpl.ArithmeticCalculator.*(..))") public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; //执行目标方法 try { //前置通知 System.out.println("前置通知"); result = pjd.proceed(); System.out.println("返回通知"); } catch (Throwable throwable) { //异常通知 System.out.println("异常通知"); //throw new RuntimeException(throwable); 抛出异常 } //后置通知 System.out.println("后置通知"); return result; }
3.切面的优先级
-
切面的优先级(@Order 注解在相同目标方法的切点方法上)
-
在切面上注解@Order(1) 数字越小优先级越高
4.重用切面表达式
//定义一个方法,用于声明切入点表达式,一般的,该方法中再不需要填入其他的代码 //使用@Pointcut来声明切入点表达式 //后面的其他通知直接使用方法名来引用当前的切入点表达式 @Pointcut("execution(public int AOPImpl.ArithmeticCalculator.*(..))") public void declareJointPointExprssion(){}
引用
@Before("declareJointPointExprssion()")
-
5.基于xml配置文件来配置AOP(不需要注解)
10.Spring对JDBC的支持
1.JDBC Template
-
配置连接池
-
配置jdbcTemplate
- Dao中直接调用jdbcTemplate的方法
@Repository //将DAO配置到IOC容器中
public class EmployeeDao {
@Autowired
private JdbcTemplate jdbcTemplate;
- update(String sql, @Nullable Object... args)
//测试Update方法:执行INSERT,UPDATE,DELETE
public void testUpdate(){
String sql = "UPDATE employees SET last_name=? WHERE id =?";
jdbcTemplate.update(sql,"Jacke",4);
}
- batchUpdate(String sql, List
//测试batchUpdate()方法:执行update的批量更新
//batchArgs为一个Object[]的List类型:因为修改一条记录需要一个Object数组
public void testBatcheUpdate(){
String sql = "INSERT INTO employees(last_name,email,dept_id) VALUES(?,?,?)";
List
- queryForObject(String sql, RowMapper rowMapper, @Nullable Object... args)
//从数据库中获取一条记录,实际得到一个对应的对象
//不是调用queryForObject(String sql, Class requiredType, Object... args) 方法
//调用queryForObject(String sql, RowMapper rowMapper, Object... args)方法
//1.其中RowMapper指定如何去映射结果集的行,常用的实现类为BeanPropertyRowMapper
//2.使用SQL中列的别名完成列名和类的属性名的映射(一一对应)类似last_name--> lastName
//3.不支持级联属性,JdbcTemplate到底是一个Jdbc的小工具,不是ORM框架
public void testQueryForObject(){
String sql = "SELECT id,last_name lastName,email FROM employees WHERE id = ?";
RowMapper rowMapper = new BeanPropertyRowMapper<>(Employee.class);
Employee employee = jdbcTemplate.queryForObject(sql,rowMapper,1);
System.out.println(employee);
}
- query(String sql, RowMapper rowMapper, @Nullable Object... args)
//查询实体类的实体
public void testQueryForList(){
String sql = "SELECT id,last_name lastName,email FROM employees WHERE id > ?";
RowMapper rowMapper = new BeanPropertyRowMapper<>(Employee.class);
List employees = jdbcTemplate.query(sql,rowMapper,4);
System.out.println(employees);
}
5.queryForObject(String sql, Class requiredType)
//获取单个列的值,或做统计查询
//使用queryForObject(String sql, Class requiredType) 方法
public void testQueryForObject2(){
String sql = "SELECT count(id) FROM employees";
long count = jdbcTemplate.queryForObject(sql,Long.class);
System.out.println(count);
}
JDBCTemplate类被设计成为线程安全的,所以可以在IOC容器中去声明它的单个实例,并将这个实例注入到所有的DAO实例中
2.NamedParameterJdbcTemplate
在Spring JDBC模板中使用具名参数,可以取代sql语句中的?占位符(当语句中多个参数时可以使代码容易维护),在NamedParameterJdbcTemplate中得到支持
- Xml中进行配置:
- 两种方式 ,一种使用map,一种使用SqlParameterSource
//可以为参数命名,与map中的键名一一对应,在参数多的时候不受顺序影响,便于维护
public void testNamedPatameterJdbcTemplate(){
String sql = "INSERT INTO employees(last_name,email,dept_id) VALUES(:ln,:email,:deptid)";
Map paramMap = new HashMap<>();
paramMap.put("email" ,"[email protected]");
paramMap.put("deptid",3);
paramMap.put("ln" ,2);
namedParameterJdbcTemplate.update(sql,paramMap);
}
//使用具名参数时,可以使用update(String sql, SqlParameterSource paramSource)方法进行更新操作
//1.语句中的参数名与对象属性名一致
//2.使用SqlParameterSource的BeanPropertySqlParameterSource实现类作为参数
public void testNamedPatameterJdbcTemplate2() {
String sql = "INSERT INTO employees(last_name,email,dept_id) VALUES(:lastName,:email,:dpid)";
Employee employee = new Employee();
employee.setLastName("jdif");
employee.setEmail("[email protected]");
employee.setDpid(3);
SqlParameterSource paramSource = new BeanPropertySqlParameterSource(employee);
namedParameterJdbcTemplate.update(sql,paramSource);
}
11.Spring中的事务管理
1.事务
用来确保数据的完整性和一致性,他是一系列动作,被当作一个单独的工作单元,要么全部完成,要么全部不起作用,例如交易的时候,库存和用户余额的变化是同步的,要么一起完成,要么都不变
Spring的核心事务管理抽象:事务管理器
2.声明式事务:
配置文件
xmlns:tx="http://www.springframework.org/schema/tx"
配置:
在启用事务的方法上加事务注解
//添加事务注解
@Transactional
@Override
public void purchase(String username, String isbn) {
//1.获取书的单价
int price = bookShopDao.findBookPriceByIsbn(isbn);
//2.更新书的库存
bookShopDao.updateBookStock(isbn);
//3.更新用户余额
bookShopDao.updateUserAccount(username,price);
}
3.事务的属性
事务的传播行为,事务的隔离级别,事务的回滚,只读,事务的过期时间
1.传播行为
传播行为:一个事务方法被另一个事务方法调用时,必须指定事务应该如何运行在另一个事务中,例如:方法可能继续在现有的事务中运行,也可能开启一个新事务,并在自己的事务中运行
由传播属性指定,Spring定义了7种类传播行为:
- REQUIRED(默认) 如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事物,并在自己的事务中运行 (整体停止,只要事务中的任意事务停止整个停止 exp:不能结账全部不买)
- REQUIRED_NEW 当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起 (事务中的事务通过时,部分代码正常运行 exp:不足结账,按账单顺序能买的买,不能则停止)
- SUPPORTS 如果有事务在运行,当前方法则在这个事务内运行,否则它可以不运行在事务中
- NOT_SUPPORTS 不能运行在事务中,如果有运行的事务,将它挂起
- MANDATORY 必须运行在事务中,如果没有正在运行的事务,抛出异常
- NEVER 不能运行在事务中,如果有运行的事务,抛出异常
- NESTED 如果有事务在运行,当前方法就应该在这个事务的嵌套事务中运行,否则,就启动一个事务,在自己的事务中运行
添加传播行为:
//propagation指定事物的传播行为,即当前事务方法被另外一个事务方法调用时
@Transactional(propagation = Propagation.REQUIRED)
2.隔离级别
最常用的isolation = Isolation.READ_COMMITTED
3.回滚(出现异常回滚使操作停止,一般不设置)
默认情况下Spring的声明式事务对所有的运行时异常进行回滚,也可以通过对应属性设置
noRollbackFor 设置那个异常不回滚
noRollbackFor = {UserAccountException.class}
4.只读
readOnly 指定是否只读,表示这个事务只读取数据但不更新数据,这样可以帮助数据库引擎优化事务,只读取数据库值的方法需要设置true
5.过期时间
timeout 指定强制回滚之前事务可以占用的时间,当方法运行时间超过事务设置的过期时间,将会强制回滚,以s为单位
timeout = 3 //过期时间三秒
4.使用xml来配置事务
- 先正常配置好bean
-
配置管理器
-
配置事务属性