Spring系列3--JdbcTemplate&事务

4. JdbcTemplate

4.1 概念

JdbcTemplate是Spring框架对JDBC进行了封装,便于数据库操作。

4.2 使用

1. 引入依赖

spring的依赖:spring-jdbc、spring-tx、spring-orm

数据库的依赖:mysql-connector-java druid

2. 在spring配置文件中配置数据库连接池和JdbcTemplate对象

database.properties文件

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/sms?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC 
jdbc.username=root
jdbc.password=root

spring配置文件

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

    <context:component-scan base-package="com.spring.demo.jdbc" />

    <context:property-placeholder location="database.properties" />

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>

</beans>

3. 创建service类,dao类,在dao中注入JdbcTemplate对象,在service类中注入dao对象。

package com.spring.demo.jdbc.service;

public interface StudentService {

    String queryUserNameById(int id);

}
package com.spring.demo.jdbc.service;

import com.spring.demo.jdbc.dao.StudentDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentDao dao;

    @Override
    public String queryUserNameById(int id) {
        return dao.findUserNameById(id);
    }
}
package com.spring.demo.jdbc.dao;

public interface StudentDao {

    String findUserNameById(int id);

}
package com.spring.demo.jdbc.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class StudentDaoImpl implements StudentDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public String findUserNameById(int id) {
        String sql = "select username from student where sid = " + id;
        return jdbcTemplate.queryForObject(sql, String.class);
    }
}

4. 测试

    @Test
    public void testJdbcTemplate() {
        ClassPathXmlApplicationContext applicationContext
            = new ClassPathXmlApplicationContext("classpath:spring_jdbc.xml");
        StudentServiceImpl studentServiceImpl =
            applicationContext.getBean("studentServiceImpl", StudentServiceImpl.class);
        String userName = studentServiceImpl.queryUserNameById(2);
        System.out.println(userName);
    }

5. 事务

5.1 概念

1. 什么是事务

数据库操作的最基本单元,逻辑上的一组操作,要么都成功,要么都失败。典型的场景:银行转账

2. 事务特性(ACID)

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

5.2 搭建事务操作场景(转账)

1. 创建表,用于存储用户的账户余额

2. 创建service,dao,完成对象的创建和注入关系

package com.spring.demo.tx.service;

public interface AccountService {

    void transfer();

}
package com.spring.demo.tx.service;

import com.spring.demo.tx.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    @Override
    public void transfer() {
         accountDao.modifyMoney("小明", - 10);
         int i = 1 / 0;
         accountDao.modifyMoney("小红", 10);
    }
}
package com.spring.demo.tx.dao;

public interface AccountDao {

    void modifyMoney(String username, int delta);

}
package com.spring.demo.tx.dao;

        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.jdbc.core.JdbcTemplate;
        import org.springframework.stereotype.Repository;

@Repository
public class AccountDaoImpl implements AccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void modifyMoney(String username, int delta) {
        String sql = "update account set money = money + " + delta + " where username = '" + username + "'";
        jdbcTemplate.update(sql);
    }
}

3. 转账过程人为加上异常

4.测试

    @Test
    public void testTx() {
        ClassPathXmlApplicationContext applicationContext
            = new ClassPathXmlApplicationContext("classpath:spring_jdbc.xml");
        AccountServiceImpl accountServiceImpl =
            applicationContext.getBean("accountServiceImpl", AccountServiceImpl.class);
        accountServiceImpl.transfer();
    }

5.测试结果

5.3 Spring中的事务操作

在5.2的场景当中,两次数据库操作中间出现了异常,导致最后的结果出现问题。因此需要,对transfer()方法添加事务,让两次数据库操作处于同一个事务当中,要么同时成功,要么同时失败。

1. 事务管理方式

编程式(写代码)和声明式(配置)

2. 原理

在spring中进行事务管理,底层使用AOP实现。

3. 基于注解的声明式事务管理实现步骤

(1)配置事务管理器 (JdbcTemplate使用DataSourceTransactionManager)

(2)引入命名空间tx

(3)开启事务注解

  

(4)在service类上面(或者其中的某个方法上)添加事务注解@Transactional

  

  @Transactional的属性:

      propagation:事务传播行为。对事务方法(会对数据做更改的方法)进行相互调用时,如何管理事务。

      

      isolation:事务隔离等级。

         脏读:一个事务读取到了另外一个事务未提交的数据

         幻读:前后两次读取的数据条数不一致,一个未提交的事务读取了另一个事务添加的数据。

         不可重复读:前后两次读取的数据内容不一致,一个未提交的事务读取了另一个事务修改的数据。

         

      timeout:超时时间。事务需要在一定的时间内提交,如果不提交就进行回滚。

      readOnly:是否只读。设置成true只能对数据进行查询操作。

      rollbackFor:回滚。设置出现哪些异常进行回滚。

      norollbackFor:不回滚。设置出现哪些异常不进行回滚。  

(5)测试

   

转账失败,数据库并未出现异常

4. 基于xml配置文件的声明式事务管理实现步骤(略)

5. 完全注解实现声明式事务管理

(1)创建配置类替代xml配置文件。

package com.spring.demo.tx.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.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
// 开启组件扫描
@ComponentScan(basePackages = {"com.spring.demo.tx"})
// 开启事务注解扫描
@EnableTransactionManagement
public class TxConfigClass {

    /**
     * 向容器中注入数据源对象
     *
     * @return 数据源对象
     */
    @Bean
    public DruidDataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/sms?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC ");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }

    /**
     * 向容器中注入JdbcTemplate对象
     *
     * @param dataSource 数据源
     * @return JdbcTemplate
     */
    @Bean
    public JdbcTemplate getJdbcTemplate(DruidDataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    /**
     * 向容器中注入DataSourceTransactionManager对象
     *
     * @param dataSource 数据源
     * @return DataSourceTransactionManager对象
     */
    @Bean
    public DataSourceTransactionManager getTransactionManager(DruidDataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

(2)测试

 

生效

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值