第五章事务
什么是事务
(1) 事务是数据库的操作最基本单元 逻辑上是一组操作。 要么都成功 如果有一个失败所有的操作都失败
典型场景
银行转钱
事务的特性(ACID)
原子性
整个操作不可分割 要么都成功 要么都失败。
一致性
操作前后的总量不变。
隔离性
多组事务操作同一条数据不会相互影响。
持久性
事务提交数据永久改变
事务操作的环境;
1 创建表 dao service bean对象的
dao
// 多钱 操作
public int addMoney(TransferBean transferBean) {
String sql = "update `transfermoney` set money = money+? where uuid=? ";
int update = jdbcTemplate.update(sql, new Object[]{transferBean.getMoney(), transferBean.getUuid()});
return update;
}
// 少钱 操作
public int removeMoney(TransferBean transferBean) {
String sql = "update `transfermoney` set money = money-? where uuid=? ";
int update = jdbcTemplate.update(sql, new Object[]{transferBean.getMoney(), transferBean.getUuid()});
return update;
}
service
// 多钱 操作
public int addMoney(TransferBean transferBean) {
return userDao.addMoney(transferBean);
}
// 少钱 操作
public int removeMoney(TransferBean transferBean) {
return userDao.removeMoney(transferBean);
}
测试
@Test
public void test17() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beanjdbctemplate.xml");
Userservice userservice = applicationContext.getBean("userservice", Userservice.class);
// 减钱
TransferBean transferBean = new TransferBean();
transferBean.setUuid("1");
transferBean.setMoney(100);
userservice.removeMoney(transferBean );
// 加钱
TransferBean transferBean1 = new TransferBean();
transferBean.setUuid("2");
transferBean.setMoney(100);
userservice.addMoney(transferBean );
}
事务场景引入
@Test
public void test17() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beanjdbctemplate.xml");
Userservice userservice = applicationContext.getBean("userservice", Userservice.class);
// 减钱
TransferBean transferBean = new TransferBean();
transferBean.setUuid("1");
transferBean.setMoney(100);
userservice.removeMoney(transferBean );
// 异常代码
int i =1/0;
// 加钱
TransferBean transferBean1 = new TransferBean();
transferBean.setUuid("2");
transferBean.setMoney(100);
userservice.addMoney(transferBean );
}
为避免上面的情况发生由此引入事务概念。
处理原理 代码方式处理
@Test
public void test17() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beanjdbctemplate.xml");
Userservice userservice = applicationContext.getBean("userservice", Userservice.class);
try {
// 开启事务
// 减钱
TransferBean transferBean = new TransferBean();
transferBean.setUuid("1");
transferBean.setMoney(100);
userservice.removeMoney(transferBean);
// 异常代码
int i = 1 / 0;
// 加钱
TransferBean transferBean1 = new TransferBean();
transferBean.setUuid("2");
transferBean.setMoney(100);
userservice.addMoney(transferBean);
//没有异常提交事务
} catch (Exception e) {
e.printStackTrace();
// 有异常关闭事务
// 关闭事务
}
}
spring方式处理事务
spring 事务操作
1 事务添加到Javaee三层结构中的service层里面
2 在spring 进行事务管理操作
有两方式 编程管理(原理方式 代码多冗余) 和 声明式管理(开发中使用)
3 声明式管理(开发中使用)
方式1 注解
方式2 xml配置方式
4 在spring进行申明事务管理 底层使用的是aop
5 spring 事务管理api接口
1提供一个接口 代表事务管理器 这个接口针对不同的框架提供不同的实现/
org.springframework.transaction
2使用声明式注解管理
1 配置spring的事务管理器
<!-- 数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql://116.205.:3306/huawei?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<!-- JdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入 dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据库事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
2 开启事务注解
引入事务支持空间
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
开启事务注解 驱动
<!-- 开启事务注解-->
<tx:annotation-driven></tx:annotation-driven>
申明类 或 方法的事务(可以发到类上 也 可以放到 方法上开启事务)
// 多钱 操作
@Transactional
public void dotransation() {
// 减钱
TransferBean transferBean2 = new TransferBean();
transferBean2.setUuid("1");
transferBean2.setMoney(100);
removeMoney(transferBean2);
// 异常代码
int i = 1 / 0;
// 加钱
TransferBean transferBean1 = new TransferBean();
transferBean1.setUuid("2");
transferBean1.setMoney(100);
addMoney(transferBean1);
}
测试
public void test18() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beanjdbctemplate.xml");
Userservice userservice = applicationContext.getBean("userservice", Userservice.class);
userservice.dotransation();
//没有异常提交事务
}
声明式事务管理参数配置
propagation:事务传播行为
isolation 事务的隔离级别
指的是在并发是情况下多事务之间不产生影响。 不考虑隔离性 产生很多问题
1有三个读的问题
脏读 不可重复读 幻读。
脏读(问题): 一个未提交的事务读取到了另一个未提交的事务数据
不可重复读(现象)
一个未提交的事务读取到了另一个事务修改提交的数据(已提交)
虚读
一个未提交的事务读取到另一个提交事务添加的数据
4 超时时间
1 事务需要在一定时间内进行提交 如果不提交就进行回滚
2 默认值是-1 设置时间也秒为单位进行计算。
5 readOnly 是否只读
1 读 查询操作 写 增删改
2 默认值为false
3 true时 只能进行查操作 其他操作禁止
6 rollebackfor
出现那些异常进行回滚
7 norollbackfor
出现那些异常不回滚
事务操作 (xml方式 事务管理)
1 配置事务管理器
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql://116.205.174.58:3306/huawei?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<!-- JdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入 dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据库事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
2 配置通知
<!--配置通知-->
<tx:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--指定那种规则的方法上添加事务-->
<tx:method name="dotransation" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
3 配置切点和切面
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql://116.205.174.58:3306/huawei?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<!-- JdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入 dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据库事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置通知-->
<tx:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--指定那种规则的方法上添加事务-->
<tx:method name="dotransation" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.test.service.Userservice.*(..))"></aop:pointcut>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
</beans>
测试
@Test
public void test19() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beanjdbctemplate2.xml");
Userservice userservice = applicationContext.getBean("userservice", Userservice.class);
userservice.dotransation();
}
完全注解开发
package com.test.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration//配置类
@ComponentScan("com.test.config")//组件扫描
@EnableTransactionManagement//开启事务
public class Txconfig {
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///user_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
}
第六章 spring5新特性
spring5新特性
1 基于jdk1.8 运行兼容 1.9
2 自带通用的日志封装
第一步
引入jar 依赖
第二步 创建log4j2配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
<!--先定义所有的appender-->
<appenders>
<!--输出日志信息到控制台-->
<console name="Console" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</console>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
第三步 使用
手动设置输出内容
Logger logger = LoggerFactory.getLogger(TestSpring5.class);
logger.debug("debug");
logger.info("info");
新特性 @nullable注解
1 注解可以使用在方法 属性 参数 表示参数返回 属性值可以为空。
2 Spring5 核心容器支持函数式风格 GenericApplicationContext //函数式风格创建对象,交给 spring 进行管理
@Test public void testGenericApplicationContext() {
//1 创建 GenericApplicationContext 对象
GenericApplicationContext context = new GenericApplicationContext();
//2 调用 context 的方法对象注册
context.refresh();
context.registerBean("user1",User.class,() -> new User());
//3 获取在 spring 注册的对象 //
User user = (User)context.getBean("com.atguigu.spring5.test.User");
User user = (User)context.getBean("user1"); System.out.println(user); }
spring5支持增和junit5
1 整合junit4
1 第一步 引入 Spring 相关针对测试依赖
2 测试
@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:bean1.xml") //加载配置文件
public class JTest4 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
}}
整合 junit5
1 第一步 引入 JUnit5 的 jar 包
2测试
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean1.xml")
public class JTest5 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
}
}
@SpringJUnitConfig(locations = "classpath:bean1.xml")
public class JTest5 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
}
}