Spring全套学习笔记
0X0a
初识Spring
1、核心概念
使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部
Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的外部(dao容器)
IOC容器负责对象的创建、出啊实话等一系列工作,被创建或被管理的对象在IOC容器中称为Bean
在容器中建立bean和bean之间的依赖关系的整个过程称为DI(依赖注入)
2、入门案例
- 目录结构
<!-- 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
1、导入Spring的坐标:spring-context, 对应的版本是5.2.10.RELEASE
2、配置bean
-->
<!-- id:给bean起名字 name:给bean起别名 scope:prototype多例对象 class:给bean定义类型 -->
<bean id="bookDao" name="dao" class="com.company.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.company.service.impl.BookServiceImpl">
<!-- name:配置的具体属性 ref:参照的Bean -->
<property name="bookDao" ref="bookDao"></property>
</bean>
</beans>
// BookDao 和 BookDaoImpl
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("BookDao...");
}
}
// BookService 和 BookServiceImpl
public interface BookService {
public void show();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDaoImpl bookDao) {
this.bookDao = bookDao;
}
public void show() {
System.out.println("ServiceDao...");
bookDao.save();
}
}
// App.java
public class App {
public static void main(String[] args) {
//1.创建IoC容器对象,加载spring核心配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2 从IOC容器中获取Bean对象(BookService对象)
BookService bookService = (BookService) context.getBean("bookService");
//3 调用Bean对象(BookService对象)的方法
bookService.show();
}
}
0X0b
bean实例化
1、FactoryBean
// BookDaoFactory.java
public class BookDaoFactory implements FactoryBean<BookDao> {
// 代替原来的实例工厂创建实例对象
public BookDao getObject() throws Exception {
return new BookDaoImpl();
}
public Class<?> getObjectType() {
return BookDao.class;
}
}
// 是否为单例对象
public boolean isSingleton() {
return true;
}
<!-- xml配置 -->
<!-- 得到的对象是BookDaoFactory里的getObject的对象 -->
<bean id="bookDao" class="com.company.factory.BookDaoFactory"/>
2、Bean生命周期控制
//BookDao.java
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("BookDao...");
}
public void init() {
System.out.println("Init...");
}
public void destory() {
System.out.println("Destory...");
}
}
<bean id="bookDao" class="com.company.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
bean销毁时机
容器关闭之前触发bean销毁
0X0c
bean注入
1、setter注入
// BookServiceImpl.java
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private int connectionNum;
private String databaseName;
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public void setBookDao(BookDaoImpl bookDao) {
this.bookDao = bookDao;
}
public void show() {
System.out.println("ServiceDao..." + connectionNum + ", " + databaseName);
bookDao.save();
}
}
<bean id="bookDao" class="com.company.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.company.service.impl.BookServiceImpl">
<!-- 引用类型 -->
<property name="bookDao" ref="bookDao"/>
<!-- 简单类型 -->
<property name="connectionNum" value="10"/>
<property name="databaseName" value="mysql"/>
</bean>
2、构造器注入
// BookServiceImpl
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private int connectionNum;
private String databaseName;
// 构造器注入,使用构造函数传参
public BookServiceImpl(BookDao bookDao, int connectionNum, String databaseName) {
this.bookDao = bookDao;
this.connectionNum = connectionNum;
this.databaseName = databaseName;
}
public void show() {
System.out.println("ServiceDao..." + connectionNum + ", " + databaseName);
bookDao.save();
}
}
<bean id="bookDao" class="com.company.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.company.service.impl.BookServiceImpl">
<!-- 引用类型 -->
<constructor-arg name="bookDao" ref="bookDao"/>
<!-- 简单类型 -->
<constructor-arg name="connectionNum" value="10"/>
<constructor-arg name="databaseName" value="mysql"/>
</bean>
3、依赖自动装配
IOC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
自动装配用于引用型依赖注入,不能对简单类型进行操作
优先级低于setter注入和构造器注入
<bean id="bookService" class="com.company.service.impl.BookServiceImpl" autowire="byType">
按照类型装配,bean对象必须唯一
<bean id="bookService" class="com.company.service.impl.BookServiceImpl" autowire="byName">
按照名称装配,bean里的id值和类里的变量名保持一致时装配
4、集合注入
<bean id="BookDao" class="com.company.dao.impl.BookDaoImpl">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>boxuegu</value>
</set>
</property>
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
</bean>
5、源对象管理
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:/localhost::3306/myDB"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
6、加载properities文件
# jdbc.properties
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://local:3306/myDB
jdbc.userName = root
jdbc.password = root
<?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
">
<!-- 1、开启context命名空间 -->
<!-- 2、使用context命名空间加载properties文件 -->
<context:property-placeholder location="jdbc.properities"/>
<!-- 3、使用属性占位符${}读取properties文件中的属性 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.userName}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
【补充 BeanFactory初始化】
// App.java
public class App {
public static void main(String[] args) {
/*
// ApplicationContext是Spring容器的核心接口,初始化时bean立即完成加载
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) context.getBean("bookService");
bookService.show();
*/
// BeanFactory是IOC容器的顶层接口,创建完毕后,所有的bean均为延迟加载
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
// 下面和此代码一样的功能:BookDao bookDao = (BookDao) bf.getBean("bookDao");
BookDao bookDao = bf.getBean("bookDao", BookDao.class);
bookDao.show();
}
}
7、核心容器总结
0X0d
注解开发
1、注解开发定义Bean
Spring提供@Component注解的三个衍生注解
* @Controller 用于表现层bean定义
* @Service 用于业务层bean定义
* @Repository 用于数据层bean定义
<!-- ApplicationContext.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 注解开发扫描含有注解开发的类 -->
<context:component-scan base-package="com.company"/>
</beans>
// BookDaoImpl.java
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
public void show() {
System.out.println("bookDao...");
}
}
// BookServiceImpl.java
@Service("bookService")
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void show() {
bookDao.show();
System.out.println("bookService...");
}
}
2、纯注解开发
// SpringConfig.java 用配置类代替了xml配置文件
package com.company.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.company")
public class SpringConfig {
}
// App.java
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
BookService bookService = context.getBean("bookService", BookService.class);
System.out.println(bookService);
}
}
3、bean作用范围和生命周期
单例对象或者多例对象
在类前加@Scope("singleton")或者prototype
对于init和destroy方法,@PostConstruct和@PreDestory放在函数的前面
4、注解开发依赖注入
// BookServiceImpl.java
@Service("bookService")
public class BookServiceImpl implements BookService {
@Autowired
// @Qualifier("bookDao")如果有多个BookDao类,我们可以根据bean的名称进行区分
private BookDao bookDao;
// 对于简单类型,使用@value即可
@value("hello") // 如果通过外部.properties文件引入值,则在配置类里加上@PropertySource("文件名"),然后@value("${对应的名称}")
private String name;
// 自动装配无需提供set方法
// public void setBookDao(BookDao bookDao) {
// this.bookDao = bookDao;
// }
public void show() {
bookDao.show();
System.out.println("bookService...");
}
}
5、注解开发管理第三方
- 方法一
// SpringConfig.java
@Configuration
public class SpringConfig {
// 1、定义一个方法获得要管理的对象
// 2、添加@Bean,表示当前方法的返回值是一个bean
@Bean("dataSource")
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost::3306/myDB");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
// APP.java
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
DataSource dataSource = context.getBean("dataSource", DataSource.class);
System.out.println(dataSource);
}
}
- 方法二
// JdbcConfig.java 独立的配置类加入核心配置
public class JdbcConfig {
@Bean("dataSource")
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost::3306/myDB");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
// SpringConfig.java 使用@Import注解手动加入配置类到核心配置
@Configuration
@Import(JdbcConfig.class)
public class SpringConfig {
}
6、注解开发总结
0X0e
Spring整合
1、整合MyBatis
-
目录结构(不需要applicationContext.xml,此为完全注解开发)
-
代码内容
//JdbcConfig.java
package com.company.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.userName}")
private String userName;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
// MybatisConfig.java
package com.company.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class MybatisConfig {
//定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.company.domain");
ssfb.setDataSource(dataSource);
return ssfb;
}
//定义bean,返回MapperScannerConfigurer对象
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.company.dao");
return msc;
}
}
// SpringConfig.java
package com.company.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
@Configuration
@ComponentScan("com.company")
@Import({JdbcConfig.class, MybatisConfig.class})
@PropertySource("jdbc.properties")
public class SpringConfig {
}
// AccountDao.java
package com.company.dao;
import com.company.domain.Account;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface AccountDao {
@Insert("insert into tbl_account(name,money)values(#{name},#{money})")
void save(Account account);
@Delete("delete from tbl_account where id = #{id} ")
void delete(Integer id);
@Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ")
void update(Account account);
@Select("select * from tbl_account")
List<Account> findAll();
@Select("select * from tbl_account where id = #{id} ")
Account findById(Integer id);
}
// Account.java
package com.company.domain;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
// AccountService.java
package com.company.service;
import com.company.domain.Account;
import java.util.List;
public interface AccountService {
void save(Account account);
void delete(Integer id);
void update(Account account);
List<Account> findAll();
Account findById(Integer id);
}
// AccountServiceImpl.java
package com.company.service.impl;
import com.company.dao.AccountDao;
import com.company.domain.Account;
import com.company.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void save(Account account) {
accountDao.save(account);
}
public void update(Account account){
accountDao.update(account);
}
public void delete(Integer id) {
accountDao.delete(id);
}
public Account findById(Integer id) {
return accountDao.findById(id);
}
public List<Account> findAll() {
return accountDao.findAll();
}
}
// App.java
package com.company;
import com.company.config.SpringConfig;
import com.company.domain.Account;
import com.company.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.sql.DataSource;
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService account = context.getBean("accountService", AccountService.class);
Account ac = account.findById(1);
System.out.println(ac);
}
}
# jdbc.properties
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://local:3306/myDB
jdbc.userName = root
jdbc.password = root
<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Spring</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- Spring操作jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!-- Spring整合Mybatis框架 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
</project>
0X0f
AOP
1、AOP简介
AOP是面相切片编程,一种编程范式
作用:在不惊动原始设计的基础上为其进行功能的增强
* 连接点(JoinPoint):正在执行的方法,例如:update()、delete()、select()等都是连接点。
* 切入点(Pointcut):进行功能增强了的方法,例如:update()、delete()方法,select()方法没有被增强所以不是切入点,但是是连接点。
* 在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
* 一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
* 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
* 通知(Advice):在切入点前后执行的操作,也就是增强的共性功能
* 在SpringAOP中,功能最终以方法的形式呈现
* 通知类:通知方法所在的类叫做通知类
* 切面(Aspect):描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法。
2、AOP入门案例
- 代码结构
// BookDao.java
public interface BookDao {
public void save();
public void update();
}
// BookDaoImpl
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("BookDao save....");
}
public void update() {
System.out.println("BookDao update....");
}
}
// MyAdvice.java
@Component
@Aspect
public class MyAdvice {
// 切入点,在执行到BookDao的update函数的时候
// 切入点定义依托一个不具有实际意义的方法进行,即五参数,无返回值,方法无实际逻辑
@Pointcut("execution(void com.company.dao.BookDao.update())")
private void pt() {}
// 绑定这个方法在切入点之前
@Before("pt()")
public void method() {
System.out.println(System.currentTimeMillis());
}
}
// SpringConfig.java
@Configuration
@ComponentScan("com.company")
// 通知Spring有用注解开发的AOP
@EnableAspectJAutoProxy
public class SpringConfig {
}
// App.java
public class App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = context.getBean("bookDao", BookDao.class);
bookDao.update();
}
}
3、切入点表达式
切入点:要进行增强的方法
切入点表达式:要进行增强的方法的描述方式
标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
通配符表达式
目的:可以使用通配符描述切入点,快速描述。
- :单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法
execution(public * com.itheima.*.UserService.find*(*))
- … :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法
execution(public User com..UserService.findById(..))
- +:专用于匹配子类类型
execution(* *..*Service+.*(..))
书写技巧
1、所有代码按照标准规范开发,否则以下技巧全部失效
2、描述切入点通常描述接口,而不描述实现类
3、访问控制修饰符针对接口开发均采用public描述(可省略访问控制修饰符描述)
4、返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用*通配快速描述
5、包名书写尽量不使用..匹配,效率过低,常用*做单个包描述匹配,或精准匹配
6、接口名/类名书写名称与模块相关的采用*匹配,例如UserService书写成*Service,绑定业务层接口名
7、方法名书写以动词进行精准匹配,名词采用*匹配,例如getById书写成getBy*,selectAll书写成select*
8、参数规则较为复杂,根据业务方法灵活调整
9、通常不使用异常作为匹配规则
4、AOP通知类型
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* com.company.dao.BookDao.show())")
public void pt() {}
@Pointcut("execution(* com.company.dao.BookDao.select())")
public void pt2() {}
// 前置通知
//@Before注解表示作为前置通知
@Before("pt()")
public void before(){
System.out.println("Before...");
}
// 在方法之后执行,有没有异常都执行
@After("pt()")
public void after(){
System.out.println("Aftering");
}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("before Around...");
// 表示对原始操作的调用,原始操作的返回值被放在了ret里
/*
* 获得执行的方法的数字签名
* Signature signature = pjp.getSignature();
* System.out.println(signature.getDeclaringType()); 输出:com.company.dao.BookDao
* System.out.println(signature.getName()); 输出:show
*/
// 获得原始操作的参数
Object[] args = pjp.getArgs();
Object ret = pjp.proceed(); // 可以写成:Object ret = pjp.proceed(args);因此参数可以改变,对参数进行修改
System.out.println("aftering Around...");
return ret;
}
// 在方法返回值之后执行,有异常不执行
@AfterReturning("pt2()")
public void afterReturning(){
System.out.println("AfterReturning");
}
// 异常之后执行
@AfterThrowing("pt()")
public void afterThrowing(){
System.out.println("AfterThrowing");
}
}
0X0g
Spring事务
1、Spring事务简介
作用:在数据层或者业务层保障一系列的数据库操作同成功同失败
// AccountDao.java
public interface AccountDao {
// 多钱的方法
@update("UPDATE users SET money = money + #{money} WHERE username = #{username}")
public void addMoney(@Param("username") String username, @Param("money") int money);
// 少钱的方法
@update("UPDATE users SET money = money - #{money} WHERE username = #{username}")
public void reduceMoney(@Param("username") String username, @Param("money") int money){
String sql = "UPDATE users SET money=money-? WHERE username=?";
jdbcTemplate.update(sql, money, username);
}
}
// AccountService.java
public interface AccountService {
// 创建事务
@Transactional
public void transfer(String out, String in, int money);
}
// AccountServiceImpl.java
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void transfer(String out, String in, int money) {
accountDao.addMoney(in, money);
accountDao.reduceMoney(in, money);
}
}
//JdbcConfig.java
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.userName}")
private String userName;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
//配置事务管理器,mybatis使用的是jdbc事务
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager dtm = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
// SpringConfig.java
@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
//开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}
2、Spring事务相关配置
3、事务传播行为
对于需要新建的事务,需要@Transactional(propagation = Propagation.REQUIRES_NEW)
//propagation设置事务属性:传播行为设置为当前操作需要新事务