学习教程框架Spring入门-04
sinarcsinxSpring入门-04
Spring整合Junit
导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13
| <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.26</version> </dependency>
|
编写测试类
在测试类上加上
**@RunWith(SpringJUnit4ClassRunner.class)**注解,指定让测试运行于Spring环境
@ContextConfiguration注解,指定Spring容器创建需要的配置文件或者配置类
1 2 3 4
| @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:配置文件1.xml")
public class SpringTest {}
|
注入对象进行测试
在测试类中注入要测试的对象,定义测试方法,在其中使用要测试的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:配置文件1.xml")
public class SpringTest { @Autowired private UserService userService; @Test public void testUserService() { userService.findById(10); } }
|
Spring整合Mybatis
我们如果想把Mybatis整合到Spring中需要使用一个整合包mybatis-spring
官方文档:http://mybatis.org/spring/zh/index.html
导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.26</version> </dependency>
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency>
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.10</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.23</version> </dependency>
|
往容器中注入整合相关对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?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 https://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="driverClassName" value="${jdbc.driver}"></property> </bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sessionFactory"> <property name="dataSource" ref="dataSource"></property> <property name="configLocation" value="classpath:mybatis-config.xml"></property> </bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer"> <property name="basePackage" value="com.sinarcsinx.dao"></property> </bean> </beans>
|
mybatis配置文件mybatis-config.xml如下:
1 2 3 4 5 6 7 8 9
| <?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> <typeAliases> <package name="com.sinarcsinx.domain"></package> </typeAliases> </configuration>
|
从容器中获取Mapper对象进行使用
1 2
| @Autowired private UserDao userDao;
|
Spring声明式事务
事务回顾
事务的概念
保证一组数据库的操作,要么同时成功,要么同时失败
四大特性
隔离性
多个事务之间要相互隔离,不能互相干扰
原子性
指事务是一个不可分割的整体,类似一个不可分割的原子
一致性
保障事务前后这组数据的状态是一致的。要么都是成功的,要么都是失败的
持久性
指事务一旦被提交,这组操作修改的数据就真的的发生变化了。即使接下来数据库故障也不应该对其有影响
实现声明式事务
如果我们自己去对事务进行控制的话我们就需要值原来核心代码的基础上加上事务控制相关的代码,而在我们的实际开发中这种事务控制的操作也是非常常见的,所以Spring提供了声明式事务的方式让我们去控制事务
只要简单的加个注解(或者是xml配置)就可以实现事务控制,不需要事务控制的时候只需要去掉相应的注解即可
案例环境准备
数据初始化
1 2 3 4 5 6 7 8 9 10
| CREATE DATABASE /*!32312 IF NOT EXISTS*/`spring_db` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `spring_db`; DROP TABLE IF EXISTS `account`; CREATE TABLE `account` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) DEFAULT NULL, `money` DOUBLE DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; INSERT INTO `account`(`id`,`name`,`money`) VALUES (1,'sin',100),(2,'arcsinx',100);
|
Spring整合Mybatis
创建Service和Dao
1 2 3 4 5 6 7 8 9
| public interface AccountService {
public void transfer(Integer outId,Integer inId,Double money); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Service public class AccountServiceImpl implements AccountService {
@Autowired private AccoutDao accoutDao;
public void transfer(Integer outId, Integer inId, Double money) { accoutDao.updateMoney(inId,money); accoutDao.updateMoney(outId,-money); } }
|
1 2 3 4
| public interface AccoutDao {
void updateMoney(@Param("id") Integer id,@Param("updateMoney") Double updateMoney); }
|
AccoutDao.xml如下:
1 2 3 4 5 6 7 8
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.sinarcsinx.dao.AccoutDao">
<update id="updateMoney"> update account set money = money + #{updateMoney} where id = #{id} </update> </mapper>
|
注解实现
配置事务管理器和事务注解驱动
在spring的配置文件中添加如下配置
1 2 3 4 5 6
| <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
<tx:annotation-driven transaction-manager="txManager"/>
|
添加注解
在需要进行事务控制的方法或者类上添加@Transactional注解就可以实现事务控制
1 2 3 4 5 6 7 8
| @Transactional public void transfer(Integer outId, Integer inId, Double money) { accoutDao.updateMoney(inId,money);
accoutDao.updateMoney(outId,-money); }
|
注意:如果加在类上,这个类的所有方法都会受事务控制,如果加在方法上,就是那一个方法受事务控制
注意,因为声明式事务底层是通过AOP实现的,所以最好把AOP相关依赖都加上
1 2 3 4 5
| <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency>
|
xml方式实现
配置事务管理器
1 2 3
| <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
|
配置事务切面
1 2 3 4 5 6 7 8 9 10 11
| <tx:advice transaction-manager="txManager" id="txAdvice"> <tx:attributes> <tx:method name="trans*"/> </tx:attributes> </tx:advice>
<aop:config> <aop:pointcut id="pt" expression="execution(* com.sinarcsinx.service..*.*(..))"></aop:pointcut> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor> </aop:config>
|
注意,因为声明式事务底层是通过AOP实现的,所以最好把AOP相关依赖都加上
1 2 3 4 5
| <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency>
|
属性配置
事务传播行为propagation
当事务方法嵌套调用时,需要控制是否开启新事务,可以使用事务传播行为来控制
测试案例:
1 2 3 4 5 6 7 8 9 10 11
| @Service public class TestServiceImpl { @Autowired AccountService accountService;
@Transactional public void test(){ accountService.transfer(1,2,10D); accountService.log(); } }
|
1 2 3 4 5 6 7 8
| public class AccountServiceImpl implements AccountService { @Transactional public void log() { System.out.println("打印日志"); int i = 1/0; } }
|
属性值 |
行为 |
REQUIRED(必须要有) |
外层方法有事务,内层方法就加入。外层没有,内层就新建 |
REQUIRES_NEW(必须要有新事务) |
外层方法有事务,内层方法新建。外层没有,内层也新建 |
SUPPORTS(支持有) |
外层方法有事务,内层方法就加入。外层没有,内层就也没有 |
NOT_SUPPORTED(支持没有) |
外层方法有事务,内层方法没有。外层没有,内层也没有 |
MANDATORY(强制要求外层有) |
外层方法有事务,内层方法加入。外层没有。内层就报错 |
NEVER(绝不允许有) |
外层方法有事务,内层方法就报错。外层没有。内层就也没有 |
例如:
1 2 3 4 5 6 7
| @Transactional(propagation = Propagation.REQUIRES_NEW) public void transfer(Integer outId, Integer inId, Double money) { accoutDao.updateMoney(inId,money); accoutDao.updateMoney(outId,-money); }
|
隔离级别isolation
Isolation.DEFAULT 使用数据库默认隔离级别
Isolation.READ_UNCOMMITTED
Isolation.READ_COMMITTED
Isolation.REPEATABLE_READ
Isolation.SERIALIZABLE
1 2 3 4 5 6 7
| @Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED) public void transfer(Integer outId, Integer inId, Double money) { accoutDao.updateMoney(inId,money); accoutDao.updateMoney(outId,-money); }
|
只读readOnly
如果事务中的操作都是读操作,没涉及到对数据的写操作可以设置readOnly为true,这样可以提高效率
1 2 3 4 5
| @Transactional(readOnly = true) public void log() { System.out.println("打印日志"); int i = 1/0; }
|