Spring
框架概述
-
轻量级开源的javaEE框架
-
可以解决企业应用开发的复杂性
-
IOC容器:控制反转,把创建对象过程交给Spring进行管理
-
AOP:面向切面,不改变源代码的情况下进行功能增强
特点
-
方便解耦,简化开发
-
AOP编程支持
-
方便程序测试
-
方便和其他框架进行整合
-
方便进行事务的操作
-
降低API开发难度
入门
-
创建普通的类,类中创建普通的方法
public class User { public void add(){ System.out.println("add~~~~~"); } }
-
创建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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置User对象创建--> <bean id="user" class="com.itxiaoli.Spring5_Demo01.User"></bean> </beans>
-
进行代码编写
public class DemoSpring5 { @Test public void testAdd(){ //1、加载Spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); //2、获取配置创建的对象 User user = context.getBean("user", User.class); System.out.println(user); user.add(); } }
IOC容器
底层原理
1、什么时IOC
-
控制反转,把对象的创建和对象之间的调用过程,交给Spring进行管理。
-
使用IOC的目的:为了耦合度降低。
-
做入门的案例就是IOC的实现
2、IOC底层原理
-
xml解析、工厂模式、反射。
3、IOC底层原理
IOC接口(BeanFactory)
-
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
-
Spring提供IOC容器实现两种方式:(两个接口)
(1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用。
特点:加载配置文件的时候不会创建对象,在获取对象(使用)的时候才会创建对象。
(2)ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用。
特点:加载配置文件时候就会把在配置文件的对象进行创建
-
ApplicationContext接口有实现类
IOC操作Bean管理
IOC操作Bean管理(基于xml)
-
创建对象
<bean id="stu" class="com.itxiaoli.demo01.Student"></bean>
-
给创建的对象赋值
1.使用setter注入
注入分为简单类型注入和引用类型注入 简单类型注入值使用value属性 引用类型注入值使用ref属性 必须要注意:使用setter注入必须提供无参的构造方法,必须提供setXXX()方法.
<!--创建学生对象--> <bean id="stu" class="com.itxiaoli.demo02.Student"> <property name="name" value="李四"></property> ===>简单类型注入 <property name="age" value="22"></property> <property name="school" ref="school"></property> ===>引用类型注入 </bean> <!--创建学校对象--> <bean id="school" class="com.itxiaoli.demo02.School"> <property name="name" value="清华大学"></property> <property name="address" value="海淀区"></property> </bean>
2、使用构造方法注入
Student stu = new Student("张三",22);
a.使用构造方法的参数名称进行注入值 <bean id="school" class="com.itxiaoli.demo03.School"> <constructor-arg name="name1" value="清华大学"></constructor-arg> <constructor-arg name="address1" value="海淀区"></constructor-arg> </bean> b.使用构造方法参数的下标注入值 <bean id="stu" class="com.itxiaoli.demo03.Student"> <constructor-arg index="0" value="钱七"></constructor-arg> <constructor-arg index="1" value="22"></constructor-arg> <constructor-arg index="2" ref="school"></constructor-arg> </bean> c.使用默认的构造方法的参数的顺序注入值 <bean id="stuSequence" class="com.itxiaoli.demo03.Student"> <constructor-arg value="陈十"></constructor-arg> <constructor-arg value="22"></constructor-arg> <constructor-arg ref="school"></constructor-arg> </bean>
IOC操作Bean管理(基于注解)
也称为DI(Dependency Injection),它是IOC的具体实现的技术.
基于注解的IOC,必须要在Spring的核心配置文件中添加包扫描.
<context:component-scan base-package="com.itxiaoli.demo01"></context:component-scan>
-
创建对象的注解
-
@Component:可以创建任意对象.创建的对象的默认名称是类名的驼峰命名法.也可以指定对象的名称@Component("指定名称").
-
@Controller:专门用来创建控制器的对象(Servlet),这种对象可以接收用户的请求,可以返回处理结果给客户端.
-
@Service:专门用来创建业务逻辑层的对象,负责向下访问数据访问层,处理完毕后的结果返回给界面层.
-
@Repository:专门用来创建数据访问层的对象,负责数据库中的增删改查所有操作.
案例: @Component("stu") //交给Spring去创建对象,就是在容器启动时创建 public class Student { @Value("张三") ===>简单类型的值注入 private String name; @Value("22") private int age; ...}
-
依赖注入的注解
1、简单类型(8种基本类型+String)的注入
@Value:用来给简单类型注入值
2、引用类型的注入
@Autowired:使用类型注入值,从整个Bean工厂中搜索同源类型的对象进行注入.
同源类型也可注入.
什么是同源类型: a.被注入的类型(Student中的school)与注入的类型是完全相同的类型 b.被注入的类型(Student中的school父)与注入的类型(子)是父子类 c.被注入的类型(Student中的school接口)与注入的类型(实现类)是接口和实现类的类型
注意:在有父子类的情况下,使用按类型注入,就意味着有多个可注入的对象.此时按照名称进 行二次筛选,选中与被注入对象相同名称的对象进行注入.
@Autowired @Qualifier("名称"):使用名称注入值,从整个Bean工厂中搜索相同名称的对象进行注入.注意:如果有父子类的情况下,直接按名称进行注入值.、
添加包扫描的方式
-
单个包扫描(推荐使用
<context:component-scan base-package="com.itxiaoli.controller"></context:component-scan> <context:component-scan base-package="com.itxiaoli.service.impl"></context:component-scan> <context:component-scan base-package="com.itxiaoli.mapper"></context:component-scan>
-
多个包扫描,多个包之间以逗号或空格或分号分隔
<context:component-scan base-package="com.itxiaoli.controller com.itxiaoli.service ,com.itxiaoli.mapper"> </context:component-scan>
-
扫描根包(不推荐)
<!--会降低容器启动的速度,导致多做无用功--> <context:component-scan base-package="com.bjpowernode"></context:component-scan>
为应用指定多个 Spring 配置文件
拆分配置文件的策略
-
按层拆
1、applicationContext_controller.xml
<bean id="uController" class="com.itxiaoli.controller.UsersController"> <bean id="bController" class="com.itxiaoli.controller.BookController">
2、applicationContext_service.xml
<bean id="uService" class="com.itxiaoli.controller.UsersService"> <bean id="bService" class="com.itxiaoli.controller.BookService">
3、applicationContext_mapper.xml
<bean id="uMapper" class="com.itxiaoli.controller.UsersMapper"> <bean id="bMapper" class="com.itxiaoli.controller.BookMapper">
-
按功能拆
1、applicationContext_users.xml
<bean id="uController" class="com.itxiaoli.controller.UsersController"> <bean id="uService" class="com.itxiaoli.controller.UsersService"> <bean id="uMapper" class="com.itxiaoli.controller.UsersMapper">
2、applicationContext_book.xml
<bean id="bController" class="com.itxiaoli.controller.BookController"> <bean id="bService" class="com.itxiaoli.controller.BookService"> <bean id="bMapper" class="com.itxiaoli.controller.BookMapper">
spring配置文件的整合
-
单个文件导入
<import resource="applicatoinContext_mapper.xml"></import> <import resource="applicatoinContext_service.xml"></import> <import resource="applicatoinContext_controller.xml"></import>
-
批量导入
<import resource="applicatoinContext_*.xml"></import>
面向切面编程AOP
AOP(Aspect Orient Programming)面向切面编程。
切面:公共的,通用的,重复的功能称为切面,面向切面编程就是将切面提取出来,单独开发,在需要调用的方法中通过动态代理的方式进行织入.
手写AOP框架
业务:图书购买业务 切面:事务
-
第一个版本:业务和切面紧耦合在一起,没有拆分.
-
第二个版本:使用子类代理的方式拆分业务和切面.
-
第三个版本:使用静态代理拆分业务和切面.业务和业务接口已拆分.此时切面紧耦合在业务中.
-
第四个版本:使用静态代理拆分业务和业务接口,切面和切面接口.
-
第五个版本:使用动态代理完成第四个版本的优化.
//最终版本 public interface Aop { default void before(){}; default void after(){}; default void exception(){}; }
public interface Service { // 规定业务功能 void buy(); // 增加有参数有返回值的方法,测试代理功能 default String show(int age){ return null; } }
public class BookServiceImpl implements Service { @Override public void buy() { System.out.println("图书购买功能实现。。。。。。"); } @Override public String show(int age) { System.out.println("这是show方法被调用"+age); return "abcd"; } }
public class TransaAop implements Aop { @Override public void before() { System.out.println("事务开启!!!"); } @Override public void after() { System.out.println("事务提交!!!"); } @Override public void exception() { System.out.println("事务回滚!!!"); }
public class ProxyFactory { public static Object getAgent(Service target,Aop aop){ // 返回生成的动态代理对象 return Proxy.newProxyInstance( // 类加载器 target.getClass().getClassLoader(), // 目标对象实现的所有的接口 target.getClass().getInterfaces(), // 代理功能的实现 new InvocationHandler() { @Override public Object invoke( // 生成的代理对象 Object proxy, // 正在被调用的目标方法 Method method, // 目标方法的参数 Object[] args) throws Throwable { Object obj = null; try { // 切面 aop.before(); //事务 日志 // 业务 obj = method.invoke(target, args); // 切面 aop.after(); } catch (IllegalAccessException e) { aop.exception(); } return obj; } } ); } }
public class productServiceImpl implements Service { @Override public void buy() { System.out.println("商品购买业务实现了"); } }
public class LogAop implements Aop { @Override public void before() { System.out.println("前置日志输出"); } }
测试
public class mytest03 { @Test public void test(){ Service agent = (Service) ProxyFactory.getAgent(new BookServiceImpl(), new TransaAop()); agent.buy(); } @Test public void test1(){ Service agent = (Service) ProxyFactory.getAgent(new BookServiceImpl(), new LogAop()); String show = agent.show(22); System.out.println(show); } }
输出
test():
事务开启!!!图书购买功能实现。。。。。。事务提交!!!
test1():
前置日志输出这是show方法被调用22abcd
Spring支持的AOP的实现
-
Before通知:在目标方法被调用前调用,涉及接口org.springframework.aop.MethodBeforeAdvice;
-
After通知:在目标方法被调用后调用,涉及接口为org.springframework.aop.AfterReturningAdvice;
-
Throws通知:目标方法抛出异常时调用,涉及接口org.springframework.aop.ThrowsAdvice;
-
Around通知:拦截对目标对象方法调用,涉及接口为org.aopalliance.intercept.MethodInterceptor。
AOP常用的术语
-
切面:就是那些重复的,公共的,通用的功能称为切面,例如:日志,事务,权限.
-
连接点:就是目标方法.因为在目标方法中要实现目标方法的功能和切面功能.
-
切入点(Pointcut):指定切入的位置,多个连接点构成切入点.切入点可以是一个目标方法,可以是一个类中的所有方法,可以是某个包下的所有类中的方法
-
目标对象:操作谁,谁就是目标对象.
-
通知(Advice):来指定切入的时机.是在目标方法执行前还是执行后还是出错时,还是环绕目标方法切入切面功能.
AspectJ框架
类型
-
前置通知@Before
-
后置通知@AfterReturning
-
环绕通知@Around
-
最终通知@After
-
定义切入点@Pointcut(了解)
切入点表达式
规范的公式: execution(访问权限 方法返回值 方法声明(参数) 异常类型) 简化后的公式: execution( 方法返回值 方法声明(参数) )
代码任意个任意的字符(通配符) .. 如果出现在方法的参数中,则代表任意参数 如果出现在路径中,则代表本路径及其所有的子路径
示例:
execution(public * *(..)) :任意的公共方法 execution(* set*(..)):任何一个以“set”开始的方法 execution(* com.xyz.service.impl.*.*(..)):任意的返回值类型,在com.xyz.service.impl包下的任意类的任意方法的任意参数 execution(* com.xyz.service..*.*(..)):任意的返回值类型 ,在com.xyz.service及其子包下的任意类的任意方法的任意参数 execution(* *..service.*.*(..)):service之前可以有任意的子包 execution(* *.service.*.*(..)):service之前只有一个包
AspectJ框架切换JDK动态代理和CGLib动态代理
<aop:aspectj-autoproxy ></aop:aspectj-autoproxy> ===>默认是JDK动态代理,取时必须使用接口类型 <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> ==>设置为CGLib子类代理,可以使用接口和实现类接 记住:使用接口来接,永远不出错.
通知
实现的步骤:
-
创建业务接口
-
创建业务实现
-
创建切面类,实现切面方法
-
在applicationContext.xml文件中进行切面绑定
添加依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.5.RELEASE</version> </dependency>
-
前置通知
package com.itxiaoli.demo01; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import java.util.ArrayList; import java.util.Arrays; /** * 此类为切面类,包含各种切面方法 */ @Aspect //交给AspectJ的框架去识别切面类 public class MyAspect { /** * 所有切面的功能求是由切面方法来实现的 * 可以将各种切面都在此类中进行开发 * * 前置通知的切面方法的规范 * 1、访问权限是public * 2、方法的返回值是void * 3、方法名称自定义 * 4、方法没有参数,如果有也是JoinPoint类型 * 5、必须使用@before注解来声明切入的时机和切入点 * 参数:vaule 指定切入点表达式 */ // @Before(value = "execution(public String com.itxiaoli.demo01.SomeServiceImpl.dosome(String,int))") @Before(value = "execution(public * com.itxiaoli.demo01.SomeServiceImpl.*(..))") public void mybefore(JoinPoint joinPoint){ System.out.println("切面方法的前置功能实现~~~~~~~~~"); System.out.println("目标方法的签名:"+joinPoint.getSignature()); System.out.println("目标方法的参数:"+ Arrays.toString(joinPoint.getArgs())); } }
-
后置通知
package com.itxiaoli.demo02; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class MyAspect { /** * 后置通知的方法规范 * 1、访问的权限是public * 2、方法没有返回值 * 3、方法名称自定义 * 4、方法有参数(也可以没有参数,如果目标方法没有返回值,则可以写无参的构造方法,但一般会写有参, * 这样可以处理无参也可以处理有参),这个切面方法的参数就是目标的方法的返回值。 * 5、使用@AfterReturning注解表明是后置通知 * 参数: * value:指定切入点表达式 * returning:指定目标方法的返回值名称,则名称必须与切面方法的参数保持一致。 * 注意: * 1、如果目标方法的返回值是八种基本类型或者是String,则不可改变返回值。 * 2、如果目标方法的返回值是引用类型,则返回值可以改变。 */ @AfterReturning(value = "execution(* com.itxiaoli.demo02.*.*(..))",returning = "object") public void myAfterReturning(Object object){ System.out.println("后置通知功能实现~~~~~~~~~~"); if (object != null){ if (object instanceof String){ object = object.toString().toUpperCase(); System.out.println("在切面方法中目标方法的返回值:"+object); } if (object instanceof Student){ Student student = (Student) object; student.setName("小李"); System.out.println("在切面方法中目标方法的返回值是"+student); } } } }
-
环绕通知
package com.itxiaoli.demo03; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class MyAspect { /** * 环绕通知方法的规范 * 1、访问权限是public * 2、切面方法有返回值,此返回值就是目标的方法的返回值 * 3、方法名称自定义 * 4、方法有参数,参数就是目标方法 * 5、回避异常Throwable * 6、使用@Around直接是声明环绕通知 * 参数: * value:指定切入点表达式 * 注意:就算是String 也能该返回值 */ @Around(value = "execution(* com.itxiaoli.demo03.*.*(..))") public Object MyAround(ProceedingJoinPoint pjp) throws Throwable { // 前切功能实现 System.out.println("环绕通知中的前置功能实现~~~~"); // 目标方法调用 Object obj = pjp.proceed(pjp.getArgs()); // 后切功能实现 System.out.println("环绕通知中的后置功能实现~~~~"); return obj.toString().toUpperCase(); //改变了目标方法的返回值 } }
-
最终通知
package com.itxiaoli.demo04; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class MyAspect { /** * 最终通知的方法的规范 * 1、访问权限是public * 2、方法没有返回值 * 3、方法名称自定义 * 4、方法没有参数,如果有也只能是JoinPoint * 5、使用@After注解表明最终通知 * 参数: * value:指定切入点表达式 */ @After(value = "execution(* com.itxiaoli.demo04.*.*(..))") public void MyAfter(){ System.out.println("最终通知!!!!!!!!!"); } }
给切入点表达式起别名@Pointcut
如果多个切面切入到同一个切入点,可以使用别名简化开发. 使用@Pointcut注解,创建一个空方法,此方法的名称就是别名.
@Aspect @Component public class MyAspect { @After(value = "mycut()") public void myAfter(){ System.out.println("最终通知的功能........"); } @Before(value = "mycut()") public void myBefore(){ System.out.println("前置通知的功能........"); } @AfterReturning(value = "mycut()",returning = "obj") public void myAfterReturning(Object obj){ System.out.println("后置通知的功能........"); } @Around(value = "mycut()") public Object myAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕通知中的前置通知的功能........"); Object obj = pjp.proceed(pjp.getArgs()); System.out.println("环绕通知中的后置通知的功能........"); return obj; } @Pointcut(value = "execution(* com.bjpowernode.s04.*.*(..))") public void mycut(){} }
SM整合的步骤
-
建表
-
新建项目,选择quickstart模板
-
修改目录
-
修改pom.xml文件,添加相关的依赖(使用老师提供)
<dependencies> <!--单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!--aspectj依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!--spring核心ioc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!--做spring事务用到的--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!--mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <!--mybatis和spring集成的依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> <!--阿里公司的数据库连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> </dependencies> <build> <!--目的是把src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中--> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes><!--包括目录下的.properties,.xml 文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory><!--所在的目录--> <includes><!--包括目录下的.properties,.xml 文件都会扫描到--> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
-
添加MyBatis相应的模板(SqlMapConfig.xml和XXXMapper.xml文件)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--读取属性文件中数据库的配置--> <properties resource="db.properties"></properties> <!--设置日志输出语句,显示相应操作的sql语名--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <typeAliases> <package name="com.bjpowernode.pojo"></package> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3308/ssm?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <package name="mapper文件所在的包名"></package> </mappers> </configuration>
-
添加SqlMapConfig.xml文件(MyBatis核心配置文件),并拷贝jdbc.propertiest属性文件到resources目录下
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=123
-
添加applicationContext_mapper.xml
-
添加applicationContext_service.xml
-
添加Users实体类,Accounts实体类
-
添加mapper包,添加UsersMapper接口和UsersMapper.xml文件并开发
-
添加service包,添加UsersService接口和UsersServiceImpl实现类
-
添加测试类进行功能测试
事务
基于注解的事务添加步骤
-
在applicationContext_service.xml文件中添加事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--因为事务必须关联数据库处理,所以要配置数据源--> <property name="dataSource" ref="dataSource"></property> </bean>
-
在applicationContext_service.xml文件中添加事务的注解驱动
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
-
在业务逻辑的实现类上添加注解@Transactional(propagation = Propagation.REQUIRED) REQUIRED表示增删改操作时必须添加的事务传播特性
@Transactional注解参数详解
@Transactional( propagation = Propagation.REQUIRED, //事务的传播 noRollbackForClassName = "ArithmeticException", //指定发生什么异常不回滚,使用的是异常的名称 noRollbackFor = ArithmeticException.class, //指定发生什么异常不回滚,使用的是异常的类型 rollbackForClassName = "", //指定发生什么异常必须回滚 rollbackFor = ArithmeticException.class, //指定发生什么异常必须回滚 timeout = -1, //连接超时设置,默认值为-1,表示永不超时 readOnly = true, //默认是false,如果是查询操作,必须设置为true isolation = Isolation.DEFAULT //使用数据库自己的隔离级别 )
Spring的两种事务处理方式
-
注解式的事务
-
声明式事务(必须掌握),在配置文件中添加一次,整个项目遵循事务的设定.
Spring中事务的五大隔离级别
-
未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
-
提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
-
可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读,但是innoDB解决了幻读
-
串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
-
使用数据库默认的隔离级别isolation = Isolation.DEFAULT
注意(面试!):
-
MySQL:mysql默认的事务处理级别是'REPEATABLE-READ',也就是可重复读
-
Oracle:oracle数据库支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别。默认系统事务隔离级别是READ COMMITTED,也就是读已提交
Spring事务的传播特性
多个事务之间的合并,互斥等都可以通过设置事务的传播特性来解决.
-
PROPAGATION_REQUIRED:必被包含事务(增删改必用)
-
PROPAGATION_REQUIRES_NEW:自己新开事务,不管之前是否有事务
-
PROPAGATION_SUPPORTS:支持事务,如果加入的方法有事务,则支持事务,如果没有,不单开事务
-
PROPAGATION_NEVER:不能运行中事务中,如果包在事务中,抛异常
-
PROPAGATION_NOT_SUPPORTED:不支持事务,运行在非事务的环境
-
PROPAGATION_MANDATORY:必须包在事务中,没有事务则抛异常
-
PROPAGATION_NESTED:嵌套事务
声明式事务
Spring非常有名的事务处理方式.声明式事务. 要求项目中的方法命名有规范
-
完成增加操作包含 add save insert set
-
更新操作包含 update change modify
-
删除操作包含 delete drop remove clear
-
查询操作包含 select find search get
<!--导入applicationContext_mappers.xml--> <import resource="applicationCintext_mapper.xml"></import> <!-- 添加包扫描--> <context:component-scan base-package="com.itxiaoli.service.impl"></context:component-scan> <!-- 添加事务管理器--> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务切面--> <tx:advice id="myadvice" transaction-manager="dataSourceTransactionManager"> <tx:attributes> <tx:method name="*select*" read-only="true"/> <tx:method name="*find*" read-only="true"/> <tx:method name="*search*" read-only="true"/> <tx:method name="*get*" read-only="true"/> <tx:method name="*insert*" propagation="REQUIRED"/> <tx:method name="*add*" propagation="REQUIRED"/> <tx:method name="*save*" propagation="REQUIRED"/> <tx:method name="*set*" propagation="REQUIRED"/> <tx:method name="*update*" propagation="REQUIRED"/> <tx:method name="*change*" propagation="REQUIRED"/> <tx:method name="*remove*" propagation="REQUIRED"/> <tx:method name="*drop*" propagation="REQUIRED"/> <tx:method name="*delete*" propagation="REQUIRED"/> <tx:method name="*clear*" propagation="REQUIRED"/> <tx:method name="*" propagation="SUPPORTS"/> </tx:attributes> </tx:advice> <!-- 绑定切面和切入点--> <aop:config> <aop:pointcut id="mycut" expression="execution(* com.itxiaoli.service.impl.*.*(..))"/> <aop:advisor advice-ref="myadvice" pointcut-ref="mycut"></aop:advisor> </aop:config> </beans>
示例
<!-- 读取属性文件jdbc.properties-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<!-- 创建数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 配置SqlSessionFactoryBean类-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 配置数据源-->
<property name="dataSource" ref="dataSource"></property>
<!-- 配置mybatis的核心配置文件-->
<property name="configLocation" value="SqlMapConfig.xml"></property>
<!-- 注册实体类的别名-->
<property name="typeAliasesPackage" value="com.itxiaoli.pojo"></property>
</bean>
<!-- 注册mapper.xml-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itxiaoli.mapper"></property>
</bean>
<!-- 导入applicationContext_mapper .xml-->
<import resource="applicationCintext_mapper.xml"></import>
<!-- SM是基于注解的开发,所以添加包扫描-->
<context:component-scan base-package="com.itxiaoli.service.impl"></context:component-scan>
<!-- 事务处理-->
<!-- 添加事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 1、因为事务必须关联数据库处理,所以要配置数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 2、添加事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!--导入applicationContext_mappers.xml-->
<import resource="applicationCintext_mapper.xml"></import>
<!-- 添加包扫描-->
<context:component-scan base-package="com.itxiaoli.service.impl"></context:component-scan>
<!-- 添加事务管理器-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务切面-->
<tx:advice id="myadvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<tx:method name="*select*" read-only="true"/>
<tx:method name="*find*" read-only="true"/>
<tx:method name="*search*" read-only="true"/>
<tx:method name="*get*" read-only="true"/>
<tx:method name="*insert*" propagation="REQUIRED"/>
<tx:method name="*add*" propagation="REQUIRED"/>
<tx:method name="*save*" propagation="REQUIRED"/>
<tx:method name="*set*" propagation="REQUIRED"/>
<tx:method name="*update*" propagation="REQUIRED"/>
<tx:method name="*change*" propagation="REQUIRED"/>
<tx:method name="*remove*" propagation="REQUIRED"/>
<tx:method name="*drop*" propagation="REQUIRED"/>
<tx:method name="*delete*" propagation="REQUIRED"/>
<tx:method name="*clear*" propagation="REQUIRED"/>
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!-- 绑定切面和切入点-->
<aop:config>
<aop:pointcut id="mycut" expression="execution(* com.itxiaoli.service.impl.*.*(..))"/>
<aop:advisor advice-ref="myadvice" pointcut-ref="mycut"></aop:advisor>
</aop:config>