【Spring5】数据库事务操作

Spring针对事务的操作

事务的概念:事务是数据库最基本的单元,逻辑上的一组操作,要么都成功,如果有一个操作失败则都失败。

事务的特性:ACID

原子性、一致性、隔离性、持久性

JavaEE环境三层结构

1.WEB视图层

2.Service业务逻辑层

主要包含一些业务逻辑

3.数据访问层

包含对数据库操作的方法,不涉及业务的操作

(1)事务添加到JavaEE三层结构的Service业务逻辑层

(2)在Spring进行事务管理操作,有两种方式:

①编程式事务管理:set autocommit = false

哪些操作会导致数据库的自动提交?

1.DDL操作一旦执行,都会自动提交,set autocommit = false对DDL操作无效。

2.DML默认情况会自动提交,可以通过set autocommit = false的方式取消DML操作的自动提交。

DML(Data Manipulation Language)数据操纵语言:

适用范围:对数据库中的数据进行一些简单操作,如insert,delete,update,select等.

DDL(Data Definition Language)数据定义语言:

适用范围:对数据库中的某些对象(例如,database,table)进行管理,如Create,Alter和Drop.

    @Test
    public void updateTest() {

        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            conn.setAutoCommit(false);

//            System.out.println(conn.getAutoCommit());

            String sql1 = "update user set balance = balance - 100 where uer=?";
            update(conn, sql1, "AA");

            System.out.println(1/0);

            String sql2 = "update user set balance = balance + 100 where uer=?";
            update(conn, sql2, "2B");

            System.out.println("转账成功");
            conn.commit();

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                if(conn!=null) {
                    conn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }


    }

声明式事务管理

基于注解方式(使用)

1.创建事务管理器 DataSourceTractionManager,并注入数据源(数据库连接池)

<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

2.在配置文件中引入名称空间tx

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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"

3.开启事务注解

<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

4.在Service中添加事务注解@Tranctional

在类上面添加此注解,则类中所有方法都添加到事务,若添加到方法上,则此方法添加到事务。

    @Transactional
    public void accountMoney(String id1, String id2, double money) {
        accountDao.reduceMoney(id1, money);

        System.out.println(1/0);

        accountDao.addMoney(id2, money);
    }

钱数不会发生变化

注解@Transactional的相关参数

1.propagation 事务传播行为

事务的传播行为,指的是多事务之间进行调用时,这个过程中的是如何管理的。

![](file://D:\资料\学习笔记\Java\Spring\2.png?msec=1649505122694)

事务的传播行为由传播属性指定。Spring定义了7种传播行为,重点记住前两个。

传播属性 描述
REQURED 如果调用方法有事务在运行,当前方法就在这个事务中运行,否则,就启动一个自己的新的事务,并在此事务中运行。(如上图)
REQURED_NEW 当前方法必须启动自己的事务,并在自己的事务中进行,如果调用方法中有事务在运行,则应该将其挂起
SUPPORTS
NOT_SUPPORTED
MANDATORY
NEVER
NESTED
@Transactional(propagation = Propagation.REQUIRED)

2.isolation 事务隔离级别

事务的隔离性,是指多事务之间操作不会受彼此影响,不考虑隔离性会产生很多问题:

①脏读:一个事务读取到了另一个未提交事务的数据(即两个事务都没有提交,事务可能回滚导致另一个事务读到脏数据)

②不可重复读:一个未提交事务读取到另一提交事务修改数据

![](file://D:\资料\学习笔记\Java\Spring\3.png?msec=1649505122695)

未提交事务的事务两次读到的数据不一致,正常情况下是不能读取数据的

脏读是一个问题,但是不可重复读是一种现象,是允许发生的

③幻读:一个未提交事务读到另一个提交事务添加的数据,两次读到的行数不一致

通过设置事务隔离级别,解决读问题

脏读 不可重复读 幻读
Read Uncommitted
(读未提交)
Read Committed
(读已提交)
Repeatable Read
(可重复读)
Serializable
(可串行化)
@Transactional(isolation = Isolation.SERIALIZABLE)

MySQL默认级别为REPEATABLE READ可重复读

3.timeout 超时时间

事务需要在一定时间内进行提交,超过这个时间就会回滚

默认值为-1,表示不超时,值以s为单位

4.readOnly 是否只读

读:查询操作

写:添加修改删除操作

5.rollbackFor 事务回滚

设置出现哪些异常进行事务的回滚

6.noRollbackFor 事务不回滚

设置出现哪些异常不进行事务的回滚

只需设置为异常的Class即可

基于XML配置文件方式

(4)在Spring进行声明式事务管理,底层使用AOP原理

(5)Spring事务管理API

完全注解开发
@Configuration //配置类
@ComponentScan(basePackages = "com.hikaru") //扫描组件
@EnableTransactionManagement //开启事务
public class TxConfig {
    @Bean
    public DruidDataSource getDataSource() throws IOException {
        DruidDataSource druidDataSource = new DruidDataSource();

        InputStream is = TxConfig.class.getClassLoader().getResourceAsStream("JDBC.properties");
        Properties properties = new Properties();
        properties.load(is);

        String driverClassName = properties.getProperty("driverClassName");
        String url = properties.getProperty("url");
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");

        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);

        return druidDataSource;
    }

    @Bean
    public DataSourceTransactionManager getTransactionManager(DruidDataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager() ;
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }

    @Bean
    public JdbcTemplate getJdbcTemplate(DruidDataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);

        return jdbcTemplate;
    }

    @Test
    public void test() throws IOException, SQLException {
        DruidDataSource druidDataSource = getDataSource();
        System.out.println(druidDataSource.getConnection());
    }
}

其中@Bean作用是将方法返回值注入IOC容器

配置类方法中的形参均在IOC容器中找到

测试

    @Test
    public void test() {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(TxConfig.class);
        AccountService accountService = context.getBean("accountService", AccountService.class);
        accountService.accountMoney("1001", "1002", 500);
    }
posted @ 2022-04-09 19:58  Tod4  阅读(386)  评论(0)    收藏  举报