框架学习的步骤
1、知道框架能做什么,Mybatis==访问数据库
2、框架的语法,框架要完成一个功能,需要一定的步骤支持
3、框架的内部实现,框架内部怎么做,原理是什么?
4、通过学习,可以实现一个框架
Spring第一个核心功能——IoC
IoC(Inversion of Control) : 控制反转
是一个理论,概念,思想
描述的是:把对象的创建、赋值、管理工作都交给代码之外的容器实现
也就是对象的创建是由其他外部资源完成
控制:创建对象,对象的属性赋值,对象之间的关系管理
正转:由开发人员在代码中,使用new构造方法创建对象,开发人员主动管理对象
public static void main(String[] args){
Student student = new Student();//正转:在代码中创建对象
}
反转:把创建对象的权限转移给代码之外的容器实现,容器来管理对象,创建对象以及给属性赋值
为什么要使用IoC
减少对代码的改动,完成不同的功能,实现解耦合。
java中创建对象有哪些方式
构造方法,new
反射
序列化
克隆
动态代理
IoC:使用容器创建对象
IoC的技术实现
DI(Dependenncy Injection)是IoC的技术实现
DI:依赖注入,只需要在程序中提供要使用的对象名称就可以
底层的实现原理是反射机制
Spring实现步骤
1、创建Maven项目
2、加入Maven依赖
加入Spring的依赖
3、创建类(接口和实现类)
和没有使用框架的时候一样,就是普通的类
4、创建spring需要使用的配置文件
声明类的信息,这些类由spring创建和管理
5、测试spring创建的类
Spring Config
这是spring的配置文件
1、beans:是根标签,在spring中,把java对象成为bean
2、spring-beans.xsd是约束文件,和mybatis中的dtd是一样的。
使用Spring来创建对象
//1、指定spring配置文件的名称
String config = "beans.xml";
//2、创建表示spring容器的对象,ApplicationContext
//ApplicationContext:表示了Spring容器
//ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
//从容器中获取某个对象,要调用对象的方法
//getBean("配置文件中bean的id值");
SomeService service = (SomeService)ac.getBean("SomeService");
service.doSome();
容器的常用方法
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
//获取容器定义的对象的数量
int nums = ac.getBeanDefinitionCounts();
//容器中每个定义的对象的名称
String nums[] = ac.getBeanDefinitionNames();
可以创建非自定义类
//创建一个Date类
<bean id="myDate" class="java.util.Date"/>
Date time = (Date) ac.getBean("myDate");
System.out.println("系统时间:" + time);
使用配置文件的方式来赋值
/*注入========赋值
简单类型:spring规定java的基本数据类型和String类型都是简单类型
di:给属性赋值
1、set注入(设值注入)。调用set方法进行赋值
*/
//(1)简单类型的set注入
<bean id="Student01" class="com.qzj.package01.Student">
<property name="name" value="张三" />//setName("李四")
<property name="age" value="21"/> //setAge("21");
//一个property只能给一个属性赋值
</bean>
//(2)引用类型的set注入
<bean id="Student01" class="com.qzj.package01.Student">
<property name="name" value="张三" />//setName("李四")
<property name="age" value="21"/> //setAge("21");
<property name="school" ref="School" //setSchool(new School);
</bean>
<bean id="School" class="xxx">
<property name=".." value=".."/>
</bean>
junit
单元测试,一个工具类库,做测试方法使用的
单元:方法,一个类中有很多方法,一个方法称为单元
构造注入:spring
构造注入:spring调用类的有参构造方法,在创建对象的同时,在构造方法汇总给属性赋值。
构造注入使用<constructor-arg>标签
<constructor-arg>标签:一个<constructor-arg>表示一个参数
<constructor-arg>标签属性:
name:表示构造方法的形参名:
index:表示构造方法的参数的位置,参数从左往右位置是0,1,2
value:构造方法的形参名类型是简单类型
ref:构造方法的形参类型是应用类型,用ref
引用类型 属性自动注入
对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为<bean/>标签
设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属
性)。根据自动注入判断标准的不同,可以分为两种:
byName:根据名称自动注入
byType: 根据类型自动注入
(1) byName 方式自动注入
当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用
byName 方式,让容器自动 注入给调用者 bean。容器是通过调用者的属性名与配置文件的被调用者的 id 进行比较而实现自动注入的。
(2) byType 方式自动注入
*java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class属性是同源关系的,
* 这样的bean能够赋值引用类型
* 同源就是同一类的意思
* 1)java中引用类型的数据类型和bean的class值是一致的。
* 2)java中引用类型的数据类型和bean的class值是父子关系的。
* 3)java中引用类型的数据类型和bean的class值是接口和实现类关系的。
包含关系的多配置文件
total表示主配置文件,包含其他配置文件,一般不定义对象
语法:<import resources="其他配置文件的路径"
关键字:"classpath:" 表示类路径(class文件所在的目录),
在spring的配置文件中要指定其他文件的位置,需要使用classpath-->
<import resource="classpath:package07/spring-student.xml"/>
<import resource="classpath:package07/spring-school.xml"/>
使用通配符
<import resource="classpath:package07/spring-*.xml"/>
1)在包含关系的配置文件中,可以使用通配符(*表示任意字符)
2)要放在同一级目录之下才可以使用通配符
3)主配置文件不能包含在内,不然会造成自己读取自己(死循环)
基于注解的di
通过注解完成对java对象的创建,属性赋值
=使用注解的步骤:
1)加入maven的依赖,spring-context,在你加入spring-context的同时,间接加入spring-aop
使用注解会用到spring-aop
2)在类中加入spring的注解(多个不同功能的注解)
3)在spring的配置文件中,加入一个组件扫描器的标签,说明注解在项目中的位置
注解的实现步骤
1、加入依赖
2、创建类,在类上加入注解
3、创建spring的配置文件
声明组件扫描器的标签,指明注解位置
4、使用注解创建对象,创建容器ac
@Component
@Component:创建对象的,等同于<bean>的功能
属性:value就是对象的名称,也就是bean的id值
value的值是唯一的,创建的对象在整个spring容器中就一个
位置:在类的上面
@Component(value="myStudent")等同于
<bean id="myStudent" class="com.qzj.pa01.Student" />
语法:
@Component(value="myStudent")
@Component("myStudent")
@Component
组件扫描器
声明组件扫描器(component-scan)组件就是对象
工作方式:spring会去扫描遍历base-package包和子包的所有类,
找到所有注解,按照功能去创建对象和属性赋值-->
<context:component-scan base-package="com.qzj.pa01"/>
和@Component功能一致,创建对象的注解还有:
1、@Respotory(用在持久层上):放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的
2、@Service(用在业务层类上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的
3、@Controller(用在控制器上面):放在控制器(处理器)类的上面,创建控制类对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果
以上三个注解的用法和语法和@component是一样的,都能创建对象,但是这三个注解还有别的功能
@Value
简单类型的属性赋值
属性:value是String类型的,表示简单类型的属性值
位置:1、在属性定义上面,无需set方法,推荐使用
2、在set方法的上面
@Autowired
引用类型的属性赋值,使用自动注入原理,支持byName,byType
@Autowired:默认使用的是byType自动注入
属性:required,是一个boolean类型,默认true
required=true(更合适):引用类型如果赋值失败,程序报错,终止执行
required=false:如果失败,正常执行,引用类型为null
位置:1)在属性定义的上面,无需set方法,推荐使用
2)在set方法的上面
如果要使用byName方式,需要做的是
1)在属性上面加入@Autowired
2)在属性上面加入@Qualifier(value="beanID")
@Autowired(required=true)
@Qualifier("mySchool")
private School school;
@Resource
来自jdk的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值
使用的也是自动注入原理,支持byName和byType, 默认是byName
先使用byName自动注入,如果byName失败,再使用byType
如果要使用byName,需要
@Resource(name="mySchool")
private School school;
位置:1、在属性定义的上面,无需set方法,推荐使用
2、在set方法上面
AOP
1、动态代理
实现方式:JDK动态代理,使用jdk中的Proxy,Method,InvocationHandler创建代理对新挨个
JDK动态代理要求目标类必须实现接口
cglib动态代理:是第三方的工具库,创建代理对象,原理是继承,通过继承目标类,创建子类
子类就是代理对象,要求目标类不能是final,方法也不能是final
2、动态代理的作用:
1)在目标类源代码不改变的情况下,增加功能
2)减少代码的重复
3)专注业务逻辑代码
4)解耦合,让你的业务功能和日志,事务非业务功能分离
3、AOP(Aspect Orient Programming)面向切面编程
Aspect: 切面,给你的目标类增加的功能,就是切面,像上面的日志、事务都是切面
切面的特点:一般都是非业务方法,独立使用的
Orien: 面向,对着
Programming: 编程
OOP: 面向对象编程
4、怎样理解面向切面编程?
1)需要在分析项目功能时,找出切面;
2)合理的安排切面的执行时间(在目标方法前,还是在目标方法后)
3)合理的安全切面执行的位置,在哪个类?哪个方法?增强功能
术语:
*Aspect:切面,表示增强的功能,就是一堆代码,完成某个功能。非业务功能,常见的切面功能
有日志,事务,统计信息,参数检查,权限验证。
JoinPoint:连接点,连接业务方法和切面的位置,就某类中的一个业务方法
*Pointcut:切入点,指多个连接点方法的集合,多个方法
目标对象,给哪个类的方法增加功能,这个类就是目标对象
* Advice:通知,通知表示切面功能执行的时间
切面三个关键要素
切面的功能代码====切面能干什么
切面的执行位置====使用Pointcut表示切面执行的位置
切面的执行时间====使用Advice表示时间,在目标方法之前,还是目标方法之后
aop的实现
aop是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
1、spring:spring在内部实现了aop规范,能做aop的工作
spring主要在事务处理时使用aop,
我们项目开发中很少使用spring的aop实现,因为spring的aop比较笨重
2、aspectJ:一个开源的,专门做aop的框架,spring框架中集成了aspectJ框架,可以通过spring使用其功能
aspectJ框架实现aop有两种方式:
1、使用xml的配置文件
2、使用注解,我们在项目中做aop功能,一般都使用注解,aspectJ有5个注解。
学习aspectJ框架的使用
1、切面的执行时间,执行时间在规范中叫做Advice(通知、增强),
在aspectJ框架中使用注解表示,也可以使用xml配置文件中的标签
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After
2、切面执行的位置,使用的是切入点表达式。
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
每个部分用空格分开,访问权限和异常类型可以省略
* 表示多个字符
.. 用在参数时表示多个参数,用在包名时表示当前包及其子包路径
+ 用在类名后,表示当前类及子类,用在接口后,表示当前接口及实现类
举例:
//指定切入点为:任意公共方法:
execution(public * *(..))
//任何一个以set开始的方法
execution(* set*(..))
//定义在service包里的任意类的任意方法
execution(* service.*.*(..))
//定义在service包或子包里的任意类的任意方法
execution(* service..*.*(..))
//指定所有包下的service子包下所有类所有方法
execution(* *..service.*.*(..))
前置通知
//@Aspect作用:表示当前类是切面类
//切面类:是用来给业务方法增加功能的类,这个类中有切面的功能代码
//位置:在类定义的上面
@Aspect
public class MyAspectJ{
/*定义方法:方法是实现切面功能的。
方法的定义要求:
1.公共方法public
2.方法没有返回值
3.方法名称自定义
4.方法可以有参数,也可以没有参数。
如果有参数,参数不是自定义的,有几个参数类型可以使用
-----------------------------------------------------------------------------------------
@Before:前置通知注解
属性:value,是切入点表达式 ,表示切面的功能执行的位置。
位道:在方法的上面
特点:
1.在目标方法之前先执行的
2.不会政变目标方法的执行结果
3.不会影响目标方法的执行。*/
@Before(value="execution(* *..SomeServiceImpl.*(..))")
public void isBefore(JoinPoint jp){
------------------------------------------------------------------------------------
/*
指定通知方法中的参数: JoinPoint
JoinPoint:业务方法,要加入切面功能的业务方法
作用:可以在通知方法中获取方法执行时的信息,例如方法名称, 方法的参数列表。
如果你的切面功能中需要用到方法的信息,就加入JoinPoint
这个Joinpoint参数的值是由框架赋予,必须是 第一个位置的参数 */
jp.getSignature();//方法的全限定名称
jp.getSignature().getName();//方法名
Object args[] = jp.getArgs();//方法的参数列表
}
}
后置通知
后置通知定义方法,方法是实现切面功能的。
方法的定义要求:
1.公共方法public
2.方法没有返回值
3.方法名称自定义
4.方法有参数的,推荐是object, 参数名自定义
/*
@AfterReturning
属性:: 1.value切入点表达式
2. returning自定义的变量,表示目标方法的返回值的。
自定义变量名必须和通知方法的形参名一样。
位置:在方法定义的上面
特点: 1.在目标方法之后执行的。
2.能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
3.可以修改这个返回值
*/
@AfterReturning(value = "execution(* *..SomeServiceImpl.*(..))",
returning = "res")
public void myAfterReturning(Object res){
Student stu = (Student)res;
stu.setName("李四");//如果返回值是一个引用类型,可以通过后置方法来修改返回值
}
环绕通知
环绕通知方法的定义格式
1.方法是公共的,public
2.必须有一个返回值,推荐使用object
3.方法名称自定义
4.方法有参效,固定的参数ProceedingJoinpoint
@Around:环绕通知
属性:value切入点表达式
位置:在方法的定义什么
特点:
1.它是功能最强的通知
2.在目标方法的前和后都能增强功能。
3.控制目标方法是否被调用执行
4.修改原来的目标方法的执行结果。 影响最后的调用结果
环绕通知,等同于jdk动态代理的,InvocationHandler接口
参数: ProceedingJoinPoint 就等同于Method
作用:执行目标方法的
返回值:就是目标方法的执行结果 ,可以被修改
@Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
//实现环绕通知
//方法之前执行,开始事务
Object args[] = pjp.getArgs();
for (Object arg: args){
if("zhangsan".equals(arg)){//控制业务方法的执行
pjp.proceed();//执行方法
}
}
//方法之前执行,提交事务
return "abc";//改变方法的返回值
}
异常通知
异常通知方法的定义格式
1.public
2.没有返回值
3.方法名称自定义
4.方法有个一个Exception,如果还有是JoinPoint,
/*
@AfterThrowing:异常通知
属性:
1.value 切入点表达式
2.throwinng 自定义的变量,表示目标方法抛出的异常对象。
3.变量名必须和方法的参数名一样
特点:
1.在目标方法抛出异常时执行的
2.可以做异常的监控程序,监控目标方法执行时是不是有异常。
3.如果有异常,可以发送邮件,短信进行通知
-------------------------------------------------------------------------*/
@AfterThrowing(value =” execution(* *. . SomeServiceImpl . doSecond(..))",
throwing = "ex" )
public void myAfterThrowing(Exception ex) {
System.out .println("异常通知:方法发生异常时,执行: "+ex. getMessage());
//发送邮件,短信, 通知开发人员
最终通知
最终通知方法的定义格式
1.public
2.没有返回值
3.方法名称自定义
4.方法没有参数,如果有就是JoinPoint,
@After :最终通知
属性: value切入点表达式
位置:在方法的上面
特点:
1.总是会执行
2.在目标方法之后执行的
3.一般用来做资源清除工作
PointCut
用途:定义和管理切入点, 如果项目中有多个重复的切入点表达式,可以使用PointCut进行代码复用。
属性:value切入点表达式
位置:在自定义的方法上面
特点:
当使用@Pointcut定义在一个方法的上面, 此时这个方法的名称就是切入点表达式的别名。
其它的通知中, value属性就可以使用这个方法名称,代替切入点表达式
@Around(value = "mypt())")
@Pointcut(value =”execution(* * .. SomeserviceImpl. doThird(..))" )
public void mypt(){
//无需代码
}
cglib代理
//目标类没有接口,使用cglib动态代理,spring框架会自动应用cglib
com.bipowernode.ba07.SomeServiceImpl$$EnhancerBySpringCGLIB$$575c8b90
*/
System.out.println("proxy:"+proxy.getClass().getName());
//通过代理的对象执行方法,实现目标方法执行时,增强了功能
proxy.doThird();
//如果你期望目标类有接口,使用cglib代理
<aop:aspectj-autoproxy proxy -target-class= "true"/>
spring继承mybatis
步骤
1.新建maven项目
2.加入maven的依赖
1 ) spring依赖
2 ) mybatis依赖
3 ) mysq1驱动
4 ) spr ing的事务的依赖
5 ) mybatis和spring集成的依赖: mybatis 官方体用的,用来在spring项目中创建mybatis
的sqlSesissonF actory, dao对象的
3.创建实体类
4.创建dao接口和mapper文件
5.创建mybatis主配置文件
6.创建Service接口和实现类, 属性是dao。
7.创建spring的配置文件:声明mybati s的对象交给spring创建
1)数据源
2 ) sqlsess ionFactory
3) Dao对象
4 )声明自定义的service
8.创建测试类,获取Service对象 ,通过service调用dao完成数据库的访问
spring的数据处理
1、什么是事务
事务是指一组sql语句的集合,集合中有多条sql语句,我们希望这些sql语句都成功或者都失败,就是事务
2、什么时候会用到事务
操作涉及到多个表,或者多个sql语句,insert,update,detele都成功
比如银行转账,张三要给李四转一百块钱
select count from t_account where name='zhangsan'
select count from t_account where name='lisi'
update t_account set money-100 where name="zhangsan"
update t_account set money+100 where name="lisi"
在java中写代码控制事务,要写在service类的业务方法中
因为业务方法会调用多个dao方法,来执行多个sql语句,可以控制这几个方法执行一个事务
jdbc访问数据库处理事务:
Connection conn;conn.commit();conn.rollback();
mybatis访问数据库处理事务
SqlSession.commit();SqlSession.rollback();
这样做的不足之处:
1、不同的数据库访问技术以及处理事务的对象方法都不一样
2、掌握多重数据库事务处理逻辑,什么时候提交回滚
3、处理事务的多种方法
总结:多种数据库的访问技术,有不同的事务处理的机制
spring创建事务处理对象-事务管理器
spring提供了处理事务的统一模型,用一个步骤,完成多种数据库访问技术的事务处理
叫做事务管理器,是一个接口与其众多实现类
PlatformTransactionManager 定义了commit、rollback
mybatis访问=DataSourceTransactionManager
hibernate访问=HibernateTransactionManager
需要在spring的配置文件中用bean标签声明
<bean id="xxx" class="..DataSourcesTransactionManager">
事务类型
一、事务的隔离级别
DEFAULT:默认级别,Mysql是REPEATABLE_READ(可重复读)
Oracle是READ_UNCOMMITTED读已提交
1、read_uncommitted :读未提交,为解决任何并发问题
2、read_committer : 读已提交,解决脏读,存在不可重复读和幻读
3、repeatable_read : 可重复读,解决脏读、不可能重复读、存在幻读
4、serializable : 串行化,不存在并发问题
二、事务的超时时间: 表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。
单位是秒, 整数值, 默认是 -1.
三、事务的传播行为 :控制业务方法是不是有事务的, 是什么样的事务的。
7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。
PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_SUPPORTS
以上三个需要掌握的
PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
四、事务提交事务,回滚事务的时机
1)当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit
2)当你的业务方法抛出运行时异常或ERROR, spring执行回滚,调用事务管理器的rollback
运行时异常的定义: RuntimeException 和他的子类都是运行时异常, 例如NullPointException , NumberFormatException
3) 当你的业务方法抛出非运行时异常, 主要是受查异常时,提交事务
受查异常:在你写代码中,必须处理的异常。例如IOException, SQLException
总结spring的事务
1、管理事务的是 事务管理和他的实现类
2、spring的事务是一个统一模型
1)指定要使用的事务管理器实现类,使用<bean>
2)指定哪些类,哪些方法需要加入事务的功能
3)指定方法需要的隔离级别,传播行为,超时
小型项目的事务(使用注解)
spring框架自己用aop实现给业务方法增加事务的功能, 使用@Transactional注解增加事务。
@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等
使用@Transactional的步骤:
1.需要声明事务管理器对象<bean id="xx" class="DataSourceTransactionManager">
2.开启事务注解驱动, 告诉spring框架,我要使用注解的方式管理事务。spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知
@Around("你要增加的事务功能的业务方法名称")
Object myAround(){
开启事务,spring给你开启
try{
buy(1001,10);
spring的事务管理器.commit();
}catch(Exception e){
spring的事务管理器.rollback();
}
}
3.在你的方法的上面加入@Trancational
<!--声明事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<!--连接的数据库,指定数据源-->
<property name="dataSource" ref="myDataSources"/>
</bean>
<!--开启事务注解驱动,告诉spring使用注解
transaction-manager 事务管理器对象的id
-->
<tx:annotation-driven transaction-manager="transactionManager" />
-------------------------------------------------------------------------
//需要添加事务的方法上方添加注解
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT,
readOnly = false,
rollbackFor = {
NoEnouchException.class,NullPointerException.class
}
)
大型项目的事务
1)要使用的是aspectj框架,需要加入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2)声明事务管理器对象
<bean id="xx" class="DataSourceTransactionManager">
3) 声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)
4) 配置aop:指定哪些哪类要创建代理。
<!--声明事务管理器-->
<bean id="transcationManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--连接的数据库指定数据源-->
<property name="dataSource" ref="myDataSources" />
</bean>
<!--声明业务方法的事务属性,隔离级别、传播行为、超过时间
id:自定义名称,表示两个标签之间配置内容的
transaction-manager:事务管理器的id
-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--tx:method:给具体的方法配置事务属性,method可以有多个,分别给不同的方法配置事务属性
name,方法名称,1)完整的方法,不带包名和类名
2)方法可以使用通配符,*表示任意字符
propagation:传播行为,枚举值
isolation:隔离级别
rollback-for:指定的异常回滚的类名(全限定名称)
-->
<tx:method name="buy" propagation="REQUIRED"
isolation="DEFAULT" read-only="false"
rollback-for="java.lang.NullPointerException,com.qzj.excep.NoEnouchException" />
</tx:attributes>
</tx:advice>
<!--使用通配符, 指定很多的方法-->
<tx:method name="add*" propagation="REQUIRES NEW" />
<!--指定修改方法-->
<tx:method name="modify*" />
<!--删除方法-->
<tx:method name="remove*" />
<!--查询方法, query , search,find-->
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
<!--配置aop-->
<aop:config>
<!--切入点表达式,指定哪些包中的类,要使用事务
id:切入点表达式的名称,唯一值
expression:切入点表达式,指定所有service包及其子包中的方法-->
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))" />
<!--配置增强器,关联advice和pointcut
advice-ref:通知,tx:advice的id
pointcut-ref:切入点表达式的id-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt" />
</aop:config>