Spring
快速开发
1.导入pom依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
2.编写需要管理的bean
//接口
public interface UserDao {
void save();
}
//实现类
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("哈哈哈哈,我是胡大头");
}
}
3.创建spring核心配置文件
applicationContext.xml
4.在spring配置文件中配置bean
<bean id="userDao" class="com.feng.Doa.Impl.UserDaoImpl"></bean>
5.使用spring的API获得bean实例
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao useDao = (UserDao) applicationContext.getBean("useDao");
useDao.save();
spring配置文件
Bean标签基本配置
用于配置对象交由Spring来创建。
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。
基本属性
id:Bean实例在spring容器中的唯一标识
class:Bean的全限定名
范围配置
scope:指对象的作用范围,取值如下
属性为singleton时,在加载配置文件时,bean就会被创建
属性为prototype时,只有在getBean时才会创建Bean
Bean生命周期配置
init-method参数
指定类中的初始化方法名称
在Bean对象被创建时,会调用
destroy-method参数
指定类中销毁方法名称
在Bean对象被销毁时,会调用
Bean实例化的三种方式
无参构造方法实例化
上述例子就是无参构造方法
工厂静态方法实例化
1.创建工厂
public class StaticFactory {
public static UserDao getUserDao(){
return new UserDaoImpl();
}
}
2.编写配置文件
<bean id="userDao" class="com.feng.factory.StaticFactory" factory-method="getUserDao"></bean>
3.创建Bean实例
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao useDao = (UserDao) applicationContext.getBean("useDao");
useDao.save();
此时,获取Bean实例就是从工厂方法getUserDao()获取的
因为是静态方法,所以,不必创建工厂实例
工厂实例方法实例化
1.创建工厂
public class DynamicFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
2.编写配置文件
<bean id="factory" class="com.feng.factory.DynamicFactory"></bean>
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>
3.创建Bean实例
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao useDao = (UserDao) applicationContext.getBean("useDao");
useDao.save();
因为不是静态方法,所以需要先有工厂实例,才能使用工厂的方法
getUserDao()获取Bean实例
Bean的依赖注入分析
在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IOC解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
如何注入
有参构造方法
1.把需要注入的对象封装为私有属性,并给出有参构造方法
注意,给出有参构造方法后,要注意默认的无参构造方法就没有了
private UserDao userDao;
public UserServiceImpl() {
}
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
2.编写配置文件
<bean id="userService" class="com.feng.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
被注入的Bean和要注入的Bean都需要在spring配置文件中配置,让spring来管理
constructor-arg标签的name指构造方法参数名,ref指要注入的Bean的id
set方法
1.把需要注入的对象封装为私有属性,并给出setXxx()方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
2.编写配置文件
<bean id="userDao" class="com.feng.Doa.Impl.UserDaoImpl"></bean>
<bean id="userService" class="com.feng.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
被注入的Bean和要注入的Bean都需要在spring配置文件中配置,让spring来管理
并且在被注入的Bean中property标签就是上面setXxx()方法中的Xxx,其中Xxx的第一个小写
ref就是要注入的Bean的id ref是引用Bean对象数据类型才用的
Bean的依赖注入的数据类型
上面的操作,都是注入的引用Bean,除了对象的引可以注入,普通数据类型,集合等都可以在容器中进行注入。
注入数据的三种数据类型
引用数据类型
上述均是引用数据类型
普通数据类型
1.私有属性,给出setXxx方法
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
2.编写配置文件
<bean id="userDao" class="com.feng.Doa.Impl.UserDaoImpl">
<property name="name" value="胡大头"></property>
<property name="age" value="18"></property>
</bean>
要注意此时,普通数据类型的set方法注入要用value
集合数据类型
1.私有属性,给出setXxx方法
private List<String> strList;
private Map<String, User> userMap;
private Properties properties;
public void setStrList(List<String> strList) {
this.strList = strList;
}
public void setUserMap(Map<String, User> userMap) {
this.userMap = userMap;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
2.编写配置文件
<bean id="userDao" class="com.feng.Doa.Impl.UserDaoImpl">
<property name="strList">
<list>
<value>胡大头1</value>
<value>胡大头2</value>
<value>胡大头3</value>
</list>
</property>
<property name="properties">
<props>
<prop key="p1">哈哈哈</prop>
<prop key="p2">嘻嘻嘻</prop>
<prop key="p3">呜呜呜</prop>
</props>
</property>
<property name="userMap">
<map>
<entry key="u1" value-ref="user1">
</entry>
<entry key="u2" value-ref="user1">
</entry>
</map>
</property>
</bean>
<bean name="user1" class="com.feng.pojo.User">
<property name="address" value="河南师范大学"></property>
<property name="emil" value="666@qq.com"></property>
</bean>
<bean name="user2" class="com.feng.pojo.User">
<property name="address" value="河南师范大学"></property>
<property name="emil" value="777 @qq.com"></property>
</bean>
引入其他配置文件
实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,而在Spring主配置文件通过import标签进行加载
<import resource="applicationContext-xxx.xml"/>
spring相关API
ApplicationContext
接口类型,代表应用上下文,可以通过其实例获得Spring容器中的Bean对象
getBean()方法
其中,当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错。
配置数据源/连接池
1.导入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
c3p0数据源
配置文件
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/smbm"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
代码编写
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
spring中加载properties文件引入数据源
1.在spring的配置文件中引入约束
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=
".............................................
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
2.引入properties配置文件
<context:property-placeholder location="classpath:jdbc.properties"/>
3.引入数据源
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
properties配置文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/smbm
username=root
password=123456
注解
原始注解
注意:
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要讲行扫描以便识别使用注解配置的类、字段和方法。
注解在service中注入dao
public interface AdminDao {
void save();
}
//@Component("adminDao")
@Repository("adminDao")
public class AdminDaoImpl implements AdminDao {
@Override
public void save() {
System.out.println("save running.......");
}
}
public interface AdminService {
void save();
}
//@Component("adminService")
@Service("adminService")
public class AdminServiceImpl implements AdminService {
@Autowired
@Qualifier("adminDao")
private AdminDao adminDao;
@Override
public void save() {
adminDao.save();
}
}
<!--配置组件扫描-->
<context:component-scan base-package="com.feng"/>
@Autowired
@Qualifier(“adminDao”)
如果只写一个@Autowired 也能注入,
它是按照数据类型从Spring容器中进行匹配的
但是如果有多个adminDao类型,就不能自动匹配了
@Qualifier(“adminDao”)
是按照id值从容器中进行匹配的但是此处@Qualifier要结合@Autowired一起使用
@Resource(name=“adminDao”)
相当于@Autowired + @Qualifier(“adminDao”)
新注解
//表明该类是Spring的核心配置类
@Configuration
//<context:component-scan base-package="com.feng"/>
@ComponentScan("com.feng")
//<context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classPath:jdbc.properties")
public class SpringConfig {
@Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${username}")
private String username;
@Value("${password}")
private String password;
@Bean("dataSource") //spring会将当前方法的返回值以指定名称存储到spring容器中
public DataSource getDateSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
}
测试类中测试
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
//注入的是UserDaoImpl,用多态的方式调用了save()方法
UserDao useDao = (UserDao) app.getBean("userDao");
UserDao useDao2 = (UserDao) app.getBean("userDao");
useDao.save();
AOP
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理 实现程序功能的统一维护的一种技术。
AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
运行期间执行
动态代理: 在不修改源码的情况下,对目标方法进行增强 完成程序间的松耦合
作用及优势
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
底层实现
实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
常用动态代理技术
JDK 代理 : 基于接口的动态代理技术
cglib 代理:基于父类的动态代理技术
目标对象是要增强方法的对象
Jdk的动态代理
1.目标接口
public interface TargetInterface {
public void save();
}
2.目标类
public class Target implements TargetInterface {
@Override
public void save() {
System.out.println("Target running....");
}
}
3.增强方法的类
public class Advice {
public void before(){
System.out.println("前置增强");
}
public void afterRunning(){
System.out.println("后置增强");
}
}
3.动态代理代码
public class PropertyTest {
public static void main(String[] args) {
Target target = new Target();
Advice advice = new Advice();
//返回值就是动态生成的代理对象
//注意生成的代理对象和目标对象的关系
//不能是目标对象类型的
TargetInterface proxy = (TargetInterface)Proxy.newProxyInstance(
//目标对象的类加载器
target.getClass().getClassLoader(),
//目标对象相同的接口字节码对象数组
//因为可能会实现多个接口,所以是数组
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
//调用代理对象的任何方法,实质执行的都是invoke()方法
//proxy 代理对象
//目标方法的方法字节码对象
//args 传递的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强方法
advice.before();
//执行目标方法
//第一个参数代表执行谁的,第二个是参数
//返回值就是目标方法的返回值
Object invoke = method.invoke(target, args);
//增强方法
advice.before();
return invoke;
}
}
);
//调用代理对象
//接口有什么方法,代理对象就有什么方法
//实际调用的是目标对象的方法
proxy.save();
}
}
cglib的动态代理
spring-context依赖集成了cjlib
1.目标方法类
public class Target {
public void save() {
System.out.println("Target running....");
}
}
2.增强方法类
public class Advice {
public void before(){
System.out.println("前置增强");
}
public void afterRunning(){
System.out.println("后置增强");
}
}
3.测试代理对象
public class PropertyTest {
public static void main(String[] args) {
//目标对象
Target target = new Target();
//增强对象
Advice advice = new Advice();
//返回值就是 动态生成的代理对象 基于cjlib
//1.创建增强器
Enhancer enhancer = new Enhancer();
//2.设置父类(目标)
enhancer.setSuperclass(Target.class);
//设置回调函数
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//执行前置
advice.before();
//执行目标
Object invoke = method.invoke(target, args);
//执行后置
advice.afterRunning();
return invoke;
}
});
//生成代理对象
Target proxy = (Target) enhancer.create();
proxy.save();
}
}
AOP相关概念
Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
AOP开发明确的事项
快速入门
1.导入 AOP 相关坐标
<!--导入spring的context坐标,context依赖aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.0.RELEASE</version>
</dependency>
<!-- aspectj的织入 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
2.创建目标接口和目标类(内部有切点)
public class Target implements TargetInterface{
@Override
public void save() {
System.out.println("Target running....");
}
}
public interface TargetInterface {
public void save();
}
3.创建切面类(内部有增强方法)
public class MyAspect {
//前置增强方法
public void before(){
System.out.println("前置代码增强.....");
}
}
4.将目标类和切面类的对象创建权交给 spring
<!--配置目标类-->
<bean id="target" class="com.feng.Target"></bean>
<!--配置切面类-->
<bean id="myAspect" class="com.feng.MyAspect"></bean>
5.在 applicationContext.xml 中配置织入关系
配置切点表达式和前置增强的织入关系
需要导入aop命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<!--配置织入: 告诉spring框架 哪些方法(切入点),需要哪些增强(前置、后置....)-->
<aop:config>
<!--声明myAspect的Bean为切面对象-->
<!--切面:切入点 加 通知(增强)-->
<aop:aspect ref="myAspect">
<!--配置Target的method方法执行时要进行myAspect的before方法前置增强-->
<aop:before method="before" pointcut="execution(public void
com.feng.Target.save())"/>
</aop:aspect>
</aop:config>
6.测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private TargetInterface target;
@Test
public void test(){
target.save();
}
}
7.结果
XML 配置 AOP 详解
首要的是需要操作的bean都要交给spring来管理
切点表达式的写法
表达式语法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
通知的类型
通知的配置语法:
<aop:通知类型 method=“切面类中方法名” pointcut=“切点表达式"></aop:通知类型>
环绕方法需要有参数 ProceedingJoinPoint pjp
这个参数就是指的是目标方法 例如
publuc Obiect around(ProceedingJoinPoint pjp){
System.out.println("环绕前代码增强.....");
//切点方法
Object obj = pjp.proceed();
System.out.println("环绕后码增强.....");
return obj;
}
切点表达式的抽取
当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽 取后的切点表达式。
<aop:config>
<!--引用myAspect的Bean为切面对象-->
<aop:aspect ref="myAspect">
<!--抽取的切点表达式-->
<aop:pointcut id="myPointcut" expression="execution(* com.feng.aop.*.*(..))"/>
<!--引用抽取的切点表达式-->
<aop:before method="before" pointcut-ref="myPointcut"></aop:before>
</aop:aspect>
</aop:config>
基于注解的AOP开发
1.创建目标接口和目标类(内部有切点)
public interface TargetInterface {
public void save();
}
public class Target implements TargetInterface {
@Override
public void save() {
System.out.println("Target running....");
}
}
2.创建切面类(内部有增强方法)
public class MyAspect {
//前置增强方法
public void before(){
System.out.println("前置代码增强.....");
}
}
3.将目标类和切面类的对象创建权交给 spring
@Component("target")
public class Target implements TargetInterface {
@Override
public void save() {
System.out.println("Target running....");
}
}
@Component("myAspect")
public class MyAspect {
public void before(){
System.out.println("前置代码增强.....");
}
}
4.在切面类中使用注解配置织入关系
@Component("myAspect")
@Aspect //标注当前myAspect是一个切面类
public class MyAspect {
@Before("execution(* com.itheima.aop.*.*(..))")
public void before(){
System.out.println("前置代码增强.....");
}
}
5.在配置文件中开启组件扫描和 AOP 的自动代理
<!--注意命名空间 context aop-->
<!--组件扫描-->
<context:component-scan base-package="com.feng.aop"/>
<!--aop的自动代理-->
<aop:aspectj-autoproxy/>
6.测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private TargetInterface target;
@Test
public void test1(){
target.save();
}
}
注解配置 AOP 详解
注解通知的类型
通知的配置语法:@通知注解(“切点表达式")
切点表达式的抽取
同 xml 配置 aop 一样,我们可以将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut 注解定义切点表达式,然后在在增强注解中进行引用。具体如下:
@Component("myAspect")
@Aspect
public class MyAspect {
@Before("MyAspect.myPoint()")
//或者@Before("myPoint()")
public void before(){
System.out.println("前置代码增强.....");
}
@Pointcut("execution(* com.feng.aop.*.*(..))")
public void myPoint(){}
}
spring事务
编程式事务控制相关对象
PlatformTransactionManager 接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。
平台事务管理器
注意:
PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类,例如:Dao 层技术是jdbc 或 mybatis 时:org.springframework.jdbc.datasource.DataSourceTransactionManager Dao 层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager
TransactionDefinition 是事务的定义信息对象,里面有如下方法:
1.隔离级别
设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读。
1.默认
2.读不可提交的
3.读可提交的
4.可重复读
5.可串行化的
2.事务传播行为
指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。
TransactionStatus 接口提供的是事务具体的运行状态 方法如下
xml声明式事务
Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明 ,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。
作用
注意:Spring 声明式事务控制底层就是AOP。
声明式事务控制的实现 要注意
1.引入tx命名空间
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
2.配置事务增强
3.配置事务 AOP 织入
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="accountDao" class="com.feng.dao.AccountDao">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--目标对象 内部方法就是切点-->
<bean id="accountService" class="com.feng.service.AccountService">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--平台事务管理器 在编程式事务中,就需要先指定平台事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--需要注入一个dataSource transactionManager的底层会从dataSource中拿出connection
进行事务的控制 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--事务增强配置 需要平台事务管理器-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--事务的aop增强 事务aop织入-->
<aop:config>
<aop:pointcut id="myPointcut" expression="execution(*
com.feng.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"></aop:advisor>
</aop:config>
4.测试事务控制转账业务代码
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
int i = 1/0;
accountDao.in(inMan,money);
}
切点方法的事务参数的配置
<!--事务增强配置-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--这里就是设置事务的属性信息-->
<tx:attributes>
<!--哪些方法被增强 -->
<!--可以对不同的方法进行不同的事物增强 -->
<tx:method name="transfer" isolation="REPEATABLE_READ"/>
<tx:method name="save" isolation="REPEATABLE_READ"/>
<!--代表以update开头的方法 -->
<tx:method name="update*" isolation="REPEATABLE_READ"/>
<!--*任意方法 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
使用注解配置声明式事务控制
1.编写 AccoutDao
@Repository("accountDao")
public class AccountDao{
@Autowired
private JdbcTemplate jdbcTemplate;
public void out(String outMan, double money) {
jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);
}
public void in(String inMan, double money) {
jdbcTemplate.update("update account set money=money+? where
name=?",money,inMan);
}
}
2.编写 AccoutService
@Service("accountService")
//在当前类上加注解代表当前类下面的所有方法都需要配置事务增强
//注解里面也能加入参数 进行事务增强的配置 所有方法都公用一套
//如果类和方法上面都有 就近原则
@Transactional(isolation = Isolation.READ_COMMITTED)
public class AccountService{
@Autowired
private AccountDao accountDao;
//在需要事物的业务方法上加注解,相当于xml配置中的aop织入方法
//里面的参数相当于xml配置中的 事物增强的配置
@Transactional(isolation = Isolation.READ_COMMITTED,propagation =
Propagation.REQUIRED)
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
int i = 1/0;
accountDao.in(inMan,money);
}
}
3.编写 applicationContext.xml 配置文件
<!—省略之前配置的datsSource、jdbcTemplate、平台事务管理器的配置 要有-->
<!--组件扫描-->
<context:component-scan base-package="com.feng"/>
<!--事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
注解配置声明式事务控制解析
applicationContext.xml配置文件解析
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--配置数据源 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:component-scan base-package="com.feng"/>
</beans>