Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
spring 特点
spring的核心模块
spring中的IOC
IOC( Inverse of Control)控制反转。是降低对象之间的耦合关系的设计思想。
DI(Dependency Injection)依赖注入,说的是创建对象实例时,同时为这个对象注入它所依赖的属性
实现过程:
1. 添加依赖包
2. 在resource目录下创建applicationContext.xml配置文件
3. 在配置文件中创建对象
4. 加载配置文件
ApplicationContext app=new ClassPathXmlApplicationContext("springApplication.xml");
Person p=(Person)app.getBean("person");
bean标签的属性
- id bean对象的唯一标识符,不能添加特殊字符
- class 指定bean对应类的全路径
- name 是bean对应对象的一个标识
- scope 执行bean对象创建模式和生命周期。scope="singleton"和scope=“prototype”
- lazy-int 是否延迟加载(true/false),true延迟加载,只有对象被调用时才会加载。false 默认值,不延迟加载,无论对象是否使用,都会被立即创建。
- init-method 加载配置文件即可完成对象的初始化方法
- destroy-method 对象销毁方法
对象创建的方式
-
无参构造
-
有参构造
非对象类型用value 引用数据类型用ref
通过参数名称来设置参数<bean name="person" class="com.java.spring.bean.Person"> <constructor-arg name="name" value="Leon"/> <constructor-arg name="phone" ref="iphone"/> </bean>
也可使用index来指定对应参数
<bean name="person" class="com.java.spring.bean.Person"> <constructor-arg index="0" value="Leon"/> <constructor-arg index="1" ref="iphone"/> </bean>
-
静态工厂方法
public class Person { public static Person createPerson(){ System.out.println("静态工厂创建Person"); return new Person(); } }
<bean name="pf" class="com.java.Person" factory-method="createPerson" />
-
非静态工厂方法
public class Users{
public Person createPerson1(){
System.out.println("非静态工厂创建Person");
return new Person();
}
}
<bean id="u2" class="com.bean.Users"></bean>
<bean id="u3" factory-method="createPerson1" factory-bean="u2"></bean>
SpringBean生命周期
1)根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。
2)利用依赖注入完成 Bean 中所有属性值的配置注入。
3)如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前
Bean 的 id 值。
4)如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂
实例的引用。
5)如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法
传入当前 ApplicationContext 实例的引用。
6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法
postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它
实现的。
7)如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。初始化
bean的时候执行,可以针对某个具体的bean进行配置。afterPropertiesSet 必须实现 InitializingBean
接口。实现 InitializingBean接口必须实现afterPropertiesSet方法。
8)如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法
postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。
10)如果在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓
存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为
scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该
Bean。
11)如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean
销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方
法对 Bean 进行销毁。
DI依赖注入
set注入值
-
基本数据类型值注入
<bean id = "p1" class="com.bean.Person"> <property name = "name" value = "leon"></property> </bean>
-
引用数据类型值注入
<bean id = "p1" class="com.bean.Person"> <property name = "phone" ref= "iphone"></property> </bean>
构造方法注入
- 通过name属性,按照参数名赋值
Public Person(String name,Phone phone){ this.name = name; this.phone = phone; }
<bean name = "person" class = "com.bean.Person"> <Constructor-arg name = "name" value = "Leon"/> <Constructor-arg name = "phone" ref= "iphone"/> </bean>
- 通过Index属性,按照参数索引注入
<bean name = "person" class = "com.bean.Person"> <Constructor-arg index= "0" value = "Leon"/> <Constructor-arg index= "1" ref= "iphone"/> </bean>
- type 注入
<bean name = "person" class = "com.bean.Person"> <Constructor-arg index= "0" value = "Leon" type="java.lang.String"/> <Constructor-arg index= "1" ref= "iphone"/> </bean>
spel spring表达式
<bean name="car" class="com.bean.Car" >
<property name="name" value="mime" />
<property name="color" value="白色"/>
</bean>
<!--利用spel引入car的属性 -->
<bean name="person1" class="com.bean.Person" p:car-ref="car">
<property name="name" value="#{car.name}"/>
<property name="age" value="#{person.age}"/>
</bean>
p命名空间注入
使用 p:属性名 通过set方法完成注入
基本数据类型 p:属性名=“值”
引用数据类型 p:属性名-ref=“bean名称”
<bean id = "p2" class = "com.bean.Person" p:name="fugui" p:age = "18" p:gender = "female"></bean>
复杂类型注入
<bean id = "u1" class = "com.bean.User>
<bean id = "p1" class = "com.bean.Person>
<!--Object[]类型 object-->
<property name = "object">
<list>
<value>object类型数组</value>
<value>123</value>
<value>object类型数组</value>
<ref bean>u1</ref><!--引用类型-->
</list>
</property>
<!--List类型 list-->
<property name = "list">
<list>
<value>张三</value>
<ref bean> u1</ref>
</list>
</property>
<!--Set类型 set-->
<property name = "set">
<set>
<value>李四</value>
<ref bean>u1</ref>
</set>
</property>
<!--Map类型 map-->
<property name = "map">
<map>
<entry key = "手机" value = "iphone"></entry>
<entry key = "对象" value-ref ="u1"></entry>
<map>
</property>
<!--java.util.Property类型 property-->
<property name = "property">
<props>
<prop key = "username">admin</prop>
<prop key = "password">123</prop>
<props>
<property>
自动注入
autowire:在创建对象时,根据autowire属性的值(byName、byType、constructor)对对象内的属性进行自动赋值。
byName 通过set方法,根据名称进行赋值,xml配置文件中创建的对象的id或名称需要与java文件中对象的属性名一致即可完成自动注入
byType 通过set方法,根据类型进行赋值,xml配置文件中创建的对象的类型需要与java文件中对象的属性类型一致即可完成自动注入 仅只能有一个对象类型相同 多个则报错
constructor 通过构造方法,xml配置文件中创建的对象会调用与其属性类型一致的对象的构造方法完成自动注入。构造方法的参数类型和id对象的类型相同,如不同则未找到报错。与byType相似,不同是通过构造方法。
注释实现IOC
1. 配置文件中添加约束
参考链接:spring-framework-5.0.8.RELEASE\docs\spring-framework-reference\html\xsdconfiguration.html
xml xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
2. 配置扫描注解
```xml
<context:component-scan base-package="com.yuzhao.spring.bean"></context:componentscan>
```
3. 添加在类名上的注解
@Component(“对象名”)
@Service(“person”) // service层
@Controller(“person”) // controller层
@Repository(“person”) // dao层
@Scope(scopeName=“singleton”) //单例对象
@Scope(scopeName=“prototype”) //多例对象
4.添加在属性上的注解
@Value("属性值")
private String name;
@Autowired //默认为byType,如果一个接口类型,同时有两个实现类,则报错,此时可以借助@Qualifier("bean name")
@Qualifier("c1")
private Car car;
//说明:@Resource 是java的注释,但是Spring框架支持,@Resource指定注入哪个名称的对象
//@Resource(name="对象名") == @Autowired + @Qualifier("name")
@Resource(name="Lamborghini")
private Car car;
5.添加在方法上的注解
@PostConstruct //等价于init-method属性
public void init(){
System.out.println("初始化方法");
}
@PreDestroy //等价于destroy-method属性
public void destroy(){
System.out.println("销毁方法");
}
AOP
AOP(Aspect Oriented Programming)即面向切面编程。即在不改变原程序的基础上为代码段增加新的功能。应用在权限认证、日志、事务。
AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP的实现机制
JDK动态代理
针对实现了接口的类产生代理。InvocationHandler接口
-
创建接口和对应实现类
public class UserServiceImpl implements UserService { public void test(){} }
-
创建动态代理类,实现InvocationHandler接口
public class agency implements InvocationHandler {
private UserService target; //目标对象
public agency(UserService target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//本方法中的其他输出输入增强
//proxy 代理方法被调用的代理实例
System.out.println("方法触发了");
//执行被代理类 原方法
Object invoke = method.invoke(target, args);
System.out.println("执行完毕了");
return invoke;
}
}
测试类
@Test
public void test1(){
//测试JDK动态代理技术
UserService us = new UserServiceImpl();
agency ag = new agency(us);
//这里不能转换成一个实际的类,必须是接口类型
UserService uservice = (UserService)Proxy.newProxyInstance(us.getClass().getClassLoader(),us.getClass().getInterfaces(),ag);
uservice.test();
}
CGlib实现代理
使用JDK创建代理有一个限制,它只能为接口创建代理实例.这一点可以从Proxy的接口方法newProxyInstance(ClassLoader loader,Class [] interfaces,InvocarionHandler h)中看的很清楚对于没有通过接口定义业务方法的类,可以使用CGLib来实现。
CGLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑.
-
添加依赖包
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
-
创建普通类
public class Users{ public void test(){ System.out.println("Users中的test方法执行"); } }
-
创建CGLib代理器
Class CglibProxy implements MethodInterceptor{
public object intercept(Obejct o,Method method,Object[] objects,MethodProxy methodProxy)throws Throwable{
System.out.println("日志开始");
//参数:Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法引用,Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用。
Object obj = methodProxy.invokeSuper(o,obejcts);
System.out.println("日志结束");
return obj;
测试
public static void main(String[] args) {
//1.创建真实对象
Users users = new Users();
//2.创建代理对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(users.getClass());
enhancer.setCallback(new CglibProxy());
Users o = (Users) enhancer.create();//代理对象
o.login();
}
Spring中使用AOP
-
添加依赖包
<groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.0.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.0.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.0.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.0.8.RELEASE</version> </dependency>
-
添加调取过程
-
创建增强类
前置增强:目标方法运行之前调用 aop:before
后置增强:目标方法运行之后调用(出现异常不调用) aop:after-returning
环绕增强:目标方法之前和之后都调用 aop:around
最终增强:目标方法运行之后调用(出现异常仍然调用) aop:after
异常增强:程序出现异常时调用 aop:after-throwing -
添加aop命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
- 配置文件
<!--1.创建目标类对象-->
<bean name="userService" class="com.service.UserServiceImpl" />
<!--2.配置增强类对象-->
<bean name="myAdvice" class="com.aop.MyAdvice" />
<!-- 3.配置将增强植入目标对象-->
<aop:config>
<aop:pointcut id="pc" expression="execution(public void com.service.ServiceImpl.*.* (..))"/>
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pc" />
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<aop:around method="around" pointcut-ref="pc" />
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<aop:after method="after" pointcut-ref="pc" />
</aop:aspect>
</aop:config>
环绕增强:
public void test(JointPoint jointPoint){
System.out.println("环绕开始");
try{
joinPoint.proceed();
}catch(Throwable throwable){
throwable.printStackTrace();
}
System.out.println("环绕结束");
}
切入点方法的定义
表达式匹配规则举例:
public * addUser(com.bean.User)😗 表示匹配所有类型的返回值
public int addUser(User u);
public String addUser (User u );
public void *(com.bean.User):*表示匹配所有方法名
public void deleteUser(User u );
public void updateUser(User u );
public void addUser (…):“…”表示匹配所有参数个数和类型
public void addUser(int a);
public void addUser(int b,int c);
*com.pb.service.*.*(..):匹配com.pb.service 包下所有类的所有方法
public void com.pb.service.A.a();
public String com.pb.service.B.a();
* com.pb.service…*(…):匹配com.pb.service 包及子包下所有类的所有方法
获得切入点信息
通过JoinPoint对象获取信息:
public before (JointPoint jp){
System.out.println("切入点对象:"+jp.getTarget().getClass().getSimpleName());
System.out.println("切入点方法:"+jp.getSignature());
System.out.println("切入点的参数:"+jp.getArgs());
}
特殊前置增强 Advisor前置增强实现步骤
适用场景:事务管理和事务开启必须使用前置增强
- 创建增强类,并实现MethodBeforeAdvice接口
- 修改ApplicationContext.xml文件
- 定义增强类和切入点
<aop:config>
<!-- 表达式是被切入的方法的表达式 -->
<aop:pointcut expression="execution(* biz.impl.*.*(..))"
id="mypoint"/>
<aop:advisor advice-ref="增强类对象的id" pointcut-ref="切入点对象的id"/>
</aop:config>
通过AspectJ实现AOP
- 创建对象(@Component)
- 启动扫描spring注解包
<context:component-scan base-package="com.yz"></context:component-scan>
- 启动spring注解外还要启动aspectJ注解方式
<aop:aspectj-autoproxy/>
- 在增强类上添加@Aspect
- 定义任意方法
@Pointcut("execution(* com.*.*(..))")
public void anyMethod(){}
@Component
@Aspect
public class MyAop {
@Pointcut("execution(public * com.yuzhao.service.UsersServiceImp.UsersServiceImp.findUser(..))")
public void test(){
}
@Before("test()")
public void before(){
System.out.println("前置增强");
}
@AfterReturning("test()")
public void after(){
System.out.println("后置增强");
}
@Around("test()")
public void around(ProceedingJoinPoint jp){
System.out.println("环绕开始");
try{
jp.proceed();
}catch(Throwable t){
t.printStackTrace();
}
System.out.println("环绕结束");
}
@After("test()")
public void myfinal(){
System.out.println("最终增强");
}
@AfterThrowing("test()")
public void exception(){
System.out.println("异常增强");
}
}
注解增强执行顺序
Spring JDBC
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
public void test1() throws Exception {
//TODO 测试jdbcTemplate简单使用
//1.创建c3p0链接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/springjdbc?useUnicode=true&CharacterEncoding=utf-8");
dataSource.setUser("root");
dataSource.setPassword("");
//创建jdbcTemplate对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//创建sql语句
String sql = "insert into role (rid , rname ,alias) value (? , ?,?);";
jdbcTemplate.update(sql,"3","visitor","游客");
}
Spring 管理 JdbcTemplate
-
创建db.properties属性文件
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8 uname=root password=
-
配置applicationContext.xml
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${driver}"/> <property name="jdbcUrl" value="${url}"/> <property name="user" value="${uname}"/> <property name="password" value="${password}"/> </bean> <bean id="studentDao" class="com.yz.dao.impl.StudentDaoImpl"> <property name="dataSource" ref="ds" ></property> </bean>
关于属性文件username的问题:
解决方式:<context:property-placeholder location="db.properties" system-properties-mode="FALLBACK"/>
FALLBACK — 默认值,不存在时覆盖
NEVER — 不覆盖 -
测试类
public class Demo2 { public static void main(String[] args) { ApplicationContext app=new ClassPathXmlApplicationContext("spring.xml"); StudentDao dao=(StudentDao) app.getBean("studentDao"); Student student = new Student(); student.setStudentId(2); student.setStudentNo("stu002"); student.setStuName("皮长山"); int insert = dao.insert(student); System.out.println(insert); /*Student student = dao.findbyid(2); System.out.println(student);*/ /* List<Student> students = dao.findall(); for (Student student : students) { System.out.println(student); }*/ } }
CRUD
//DQL 查询单个
jdbcTemplate.queryForObject(String var1, RowMapper var2, Object… var3);
public Users findbyid(int uid) {
String sql="select * from users where userid=?";
Users users=getJdbcTemplate().queryForObject(sql, new Object[]{uid}, new RowMapper<Users>() {
public Users mapRow(ResultSet resultSet, int i) throws SQLException {
Users users=new Users();
try {
users.setUsername(resultSet.getString("username"));
users.setPassword(resultSet.getString("password"));
users.setUserid(resultSet.getInt("userid"));
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
});
return users;
}
jdbcTemplate.query(String var1, RowMapper var2, Object… var3); //查询所有
public List<Users> findAll() {
String sql="select * from users ";
List<Users> users=getJdbcTemplate().queryForList(sql, new RowMapper<Users>() {
public Users mapRow(ResultSet resultSet, int i) throws SQLException {
Users users=new Users();
try {
users.setUsername(resultSet.getString("username"));
users.setPassword(resultSet.getString("password"));
users.setUserid(resultSet.getInt("userid"));
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
});
return users;
}
Spring 事务管理
什么是事务(Transaction)
通过sql将逻辑相关的一组操作绑定在一起,以便服务器 保持数据的完整性(准确性)。
事务通常是以begin transaction开始,以commit或rollback结束。
事务执行的流程:开启事务->执行insert,update,delete->commit/rollback
事务的特性ACID
1 - 原子性(atomicity)
事务是数据库的逻辑工作单位,而且是必须是原子工作单位,对于其数据修改,要么全部执行,要么全部不执行。
2、一致性(consistency)
事务在完成时,必须是所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。
3、隔离性(isolation)
一个事务的执行不能被其他事务所影响。企业级的数据库每一秒钟都可能应付成千上万的并发访问,因而带来了并发控制的问题。
4、持久性(durability)
一个事务一旦提交,事务的操作便永久性的保存在DB中。即使此时再执行回滚操作也不能撤消所做的更改
事务的传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
事务传播失效的情况:
spring事务是基于代理来实现的,所以:
(1)private、final、static 方法无法被代理,所以添加事务无效
(2)当绕过代理对象, 直接调用添加事务管理的方法时, 事务管理将无法生效。比如直接new出的对象。
(3)在同一个类下,有2个方法,A、B,A没有事务,B有事务,但是A调用B时,方法B被标记的事务无效。 究其原因,因为此类的调用对象为代理对象,代理方法A调用真正的被代理方法A后,在被代理方法A中才会去调用方法B,此时this对象为被代理的对象,所以是不会通知到代理对象,也就变成了第二种情况,绕过了代理对象。所以无效。
事务的隔离级别
MySQL数据库共定义了四种隔离级别:
- Serializable(串行化):可避免脏读、不可重复读,幻读情况的发生。
- Repeatable read(可重复读):可避免脏读、不可重复读情况的发生。
- Read committed(读已提交):可避免脏读情况发生。
- Read uncommitted(读未提交):最低级别,以上情况均无法保证。
事务的实现
添加tx命名空间
添加事务相关配置 修改applicationContext.xml
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driver}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="user" value="${uname}"/>
<property name="password" value="${password}"/>
</bean>
<bean id="studentDao" class="com.yz.dao.impl.StudentDaoImpl">
<property name="dataSource" ref="ds" ></property>
</bean>
<!--声明式事务-->
<!-- 1.创建事务管理器对象-->
<bean id="mytx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"></property>
</bean>
<!--2.指定哪些方法需要进行事务管理-->
<tx:advice id="myad" transaction-manager="mytx">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--3.使用面向切面的思想指定哪层需要事务管理,事务添加在service层最合理-->
<aop:config>
<aop:pointcut id="mypc" expression="execution(* com.xzk.dao.*.*(..))"></aop:pointcut>
<aop:advisor advice-ref="myad" pointcut-ref="mypc"></aop:advisor>
</aop:config>
注解事务管理
- 配置applicationContext.xml
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 对标注@Transactional注解的Bean进行加工处理,以织入事物管理切面 -->
<tx:annotation-driven transaction-manager="transactionManager" />
- 基于@Transactional默认的属性.
- 事务传播行为: PROPAGATION_REQUIRED.
- 事务隔离级别: ISOLATION_DEFAULT.
- 读写事务属性:读/写事务.
- 超时时间:依赖于底层的事务系统默认值
- 回滚设置:任何运行期异常引发回滚,任何检查型异常不会引发回滚.
默认值可能适应大部分情况,但是我们依然可以可以自己设定属性,具体属性表如下: - 在何处标注@Transactional注解?
@Transactional注解可以直接用于接口定义和接口方法,类定义和类的public方法上.但Spring建议在业务实现类上使用@Transactional注解,当然也可以添加到业务接口上,但是这样会留下一些容易被忽视的隐患,因为注解不能被继承,所以业务接口中标注的@Transactional注解不会被业务类实现继承.