JdbcTemplate

JdbcTemplate

spring 提供了一个操作数据库(表)功能强大的类 JdbcTemplate 。

我们可以用 ioc 容器来配置一个 jdbcTemplate 对象,使用它来完成对数据库表的各种操作。

1. 快速入门

1)导入依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.8</version>
</dependency>

2)创建配置文件src/jdbc.properties

jdbc.userName=root
jdbc.password=83929317fan
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/home_furnishing

3)创建配置文件src/jdbc_ioc.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"
       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"/>
    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.userName}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
    </bean>
    
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 将上面的数据源分配给 jdbcTemplate -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

4)测试

@Test
public void test01(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc_ioc.xml");
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);
    RowMapper<Member> rowMapper = new BeanPropertyRowMapper<>(Member.class);
    String sql = "select * from member";
    List<Member> res = jdbcTemplate.query(sql, rowMapper);
    System.out.println(res);
}

2. CRUD

2.1 添加

@Test
public void test01(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc_ioc.xml");
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);
    String sql = "insert into member(username,password,email) values(?,?,?)";
    int update = jdbcTemplate.update(sql, "lin123", "123", "123@qq.com");
    System.out.println(update);
}

2.2 修改

@Test
public void test01(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc_ioc.xml");
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);
    String sql = "UPDATE member SET email = ? WHERE id=?";
    int update = jdbcTemplate.update(sql, "123456@qq.com", "21");
    System.out.println(update);
}

2.3 查询

@Test
public void test01(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc_ioc.xml");
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);
    RowMapper<Member> rowMapper = new BeanPropertyRowMapper<>(Member.class);
    String sql = "select * from member";
    List<Member> res = jdbcTemplate.query(sql, rowMapper);
    System.out.println(res);

}

2.4 删除

@Test
public void test01(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc_ioc.xml");
    JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);
    String sql = "delete from member where id =?";
    int update = jdbcTemplate.update(sql, 21);
    System.out.println(update);
}

3. NamedParameterJdbcTemplate

NamedParameterJdbcTemplateJdbcTemplate 的一个扩展,它支持使用命名参数而不是传统的 JDBC “?” 占位符。这种方式使得 SQL 语句更加易于理解和维护,特别是当有很多参数需要传递给 SQL 语句时。

1)修改src/jdbc_ioc.xml

<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    <!-- 这里需要使用构造器关联数据源 -->
    <constructor-arg name="dataSource" ref="dataSource"/>
</bean>

2)使用map完成添加

@Test
public void test01(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc_ioc.xml");
    NamedParameterJdbcTemplate namedParameterJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);
    String sql = "INSERT INTO member VALUES(:id, :username, :password,:email)";
    Map<String, Object> map_parameter = new HashMap<String, Object>();
    map_parameter.put("id", 800);
    map_parameter.put("username", "lxg");
    map_parameter.put("password", "lxg123456");
    map_parameter.put("email", "123456@qq.com");
    namedParameterJdbcTemplate.update(sql, map_parameter);
}

3)使用sqlparametersoruce 来封装具名参数

@Test
public void test01(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc_ioc.xml");
    NamedParameterJdbcTemplate namedParameterJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);
    String sql = "INSERT INTO member VALUES(:id, :username, :password,:email)";
    Member member = new Member(900, "lxg1", "lxg1", "lxg1@qq.com");
    SqlParameterSource source = new BeanPropertySqlParameterSource(member);
    namedParameterJdbcTemplate.update(sql, source);
}

4. 声明式事务

Spring框架中的声明式事务管理是一种基于AOP(面向切面编程)的事务管理方式,它允许开发者通过声明的方式来管理事务,而不是通过编程的方式。这样做的好处是,业务代码与事务管理代码分离,提高了代码的可读性和可维护性。

在Spring中,声明式事务通常是通过使用@Transactional注解或者XML配置来实现的。

4.1 @Transactional 注解

@Transactional注解可以被添加到接口定义、类定义、方法定义上。

当在一个类或方法上使用@Transactional注解时,Spring会在运行时自动创建一个代理对象来管理事务。

这个注解有多个属性,比如:

  • propagation:事务的传播行为。
  • isolation:事务的隔离级别。
  • timeout:事务的超时时间限制。
  • readOnly:标记事务是否为只读事务。
  • rollbackFor:定义哪些异常会触发事务回滚。
  • noRollbackFor:定义哪些异常不会触发事务回滚。

4.2 快速入门

1)配置jdbc_ioc.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" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" 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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 引入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.userName}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 将上面的数据源分配给 jdbcTemplate -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 配置事务管理器 -->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 开启基于注解的声明式事务功能 -->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
    <!-- 加入自动扫描包 dao -->
    <context:component-scan base-package="com.lhs.component"/>
</beans>

2)创建UserDao

@Repository
public class UserDao {
    @Autowired
    JdbcTemplate jdbcTemplate;
    public int addMember(Member member){
        String sql = "insert into member values(?,?,?,?)";
        return jdbcTemplate.update(sql,member.getId(),member.getUsername(),member.getPassword(),member.getEmail());
    }
    public int addAdmin(Member member){
        String sql = "insert into admin values(?,?,?)";
        return jdbcTemplate.update(sql,member.getId(),member.getUsername(),member.getPassword());
    }
}

3)创建UserService并开启事务

@Service
@Transactional
public class UserService {
    @Autowired
    private UserDao userDao;

    public void addMember(Member member){
        System.out.println(userDao.addMember(member));
        System.out.println(userDao.addAdmin(member));
    }
}

4)测试

@Test
public void test02(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("jdbc_ioc.xml");
    UserService userService = ioc.getBean("userService", UserService.class);
    Member member = new Member(200, "lxg123456", "lxg123456", "lxg123456@qq.com");
    userService.addMember(member);
}

4.3 事务传播机制种类

REQUIREDREQUIRES_NEW是Spring中两种最常用的事务传播行为,它们定义了事务的边界以及方法如何与现有事务关联。

以下是Spring支持的事务传播机制的种类:

  1. REQUIRED(默认)
    • 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  2. SUPPORTS
    • 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式执行。
  3. MANDATORY
    • 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  4. REQUIRES_NEW
    • 总是启动一个新的事务,如果当前存在事务,则将当前事务挂起。
  5. NOT_SUPPORTED
    • 总是以非事务方式执行,如果当前存在事务,则将当前事务挂起。
  6. NEVER
    • 总是以非事务方式执行,如果当前存在事务,则抛出异常。
  7. NESTED
    • 如果当前存在事务,则在嵌套事务内执行。如果当前事务不存在,则表现同REQUIRED
    • 嵌套事务是一个子事务,它依赖于包含它的事务。嵌套事务开始执行时,它将取得一个保存点,如果嵌套事务回滚,它将回滚到这个保存点。嵌套事务的提交不会导致包含它的事务的提交。

下面是一个使用@Transactional注解和REQUIRED以及REQUIRES_NEW传播行为的示例:

@Service
public class TransactionalService {

    @Transactional(propagation = Propagation.REQUIRED)
    public void outerMethod() {
        // 代码片段A
        innerMethod();
        // 代码片段B
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void innerMethod() {
        // 代码片段C
    }
}
  • outerMethod被调用时,若发生回滚则所有子事务都会回滚。
  • innerMethod被调用时,若其中一个子事务发生回滚不会影响到其他子事务的正常执行。

4.4 事务的隔离级别

事务的隔离级别是数据库事务属性,用来定义一个事务可能受其他并发事务影响的程度。数据库事务必须具备ACID属性(原子性、一致性、隔离性、持久性),而隔离级别主要关注隔离性,防止多个事务并发执行时产生的问题,如脏读、不可重复读和幻读。

SQL标准定义了四个隔离级别:

  1. READ UNCOMMITTED(读未提交)

    • 最低的隔离级别,允许事务读取未被其他事务提交的数据。这可能导致“脏读”,即一个事务可能读取到另一个事务未提交的更改。
  2. READ COMMITTED(读已提交)

    • 允许事务读取并返回其他事务已提交的数据。这种隔离级别可以避免脏读,但是可能出现“不可重复读”,即在同一个事务内,多次读取同一数据集合时,可能会读到不同的数据(因为其他事务在这两次读取之间修改了这些数据并提交)。
  3. REPEATABLE READ(可重复读)

    • 确保在一个事务内多次读取同一数据集合的结果是一致的,即不会发生不可重复读。但是,这个级别不能防止“幻读”,即一个事务读取了几行数据,另一个并发事务插入了一些新行,当第一个事务再次读取相同的数据集合时,会发现有新的行。
  4. SERIALIZABLE(可串行化)

    • 最高的隔离级别,它完全隔离事务,使得它们不能并发执行。这个级别可以防止脏读、不可重复读和幻读。但是,这种隔离级别通常会降低并发性能,因为它会在事务操作的数据上加锁,防止其他事务的访问。

默认的隔离级别, 就是 mysql 数据库默认的隔离级别 一般为 REPEATABLE_READ

在Spring中,可以通过@Transactional注解的isolation属性来设置事务的隔离级别,例如:

@Transactional(isolation = Isolation.READ_COMMITTED)
public void someTransactionalMethod() {
    ...
}

4.5 事务的超时回滚

可通过timeout来设置超时回滚时间

@Transactional(timeout = 2)
public void someTransactionalMethod() {
    ...
}
  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林小果呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值