Learn Spring - Spring DAO

本文介绍Spring事务管理的基础知识,包括DAO异常体系、事务传播行为等,并通过一个具体的JDBC编程示例展示了如何在Spring环境中进行数据库操作。

1. 概念

  1. Spring的DAO异常体系建立在运行期异常的基础上,封装了源异常

  2. JDBC数据访问流程:

    • 准备资源

    • 启动事务

    • 在事务中执行具体数据访问操作

    • 提交/回滚事务

    • 关闭资源,处理异常

  3. Spring将相同的数据访问流程固化到模板类中,把数据访问中固定和变化的部分分开,同时保证模板类是线程安全的。Spring为不同的持久化技术都提供了简化操作的模板和回调

  4. 数据库事务:原子性,一致性,隔离性和持久性(ACID)

  5. 5类数据库并发问题:

    • 脏读:A事务读取到B事务尚未提交的数据

    • 不可重复读:A事务中读取到B事务已经提交的==更新==数据,即连续两次读取结果不同

    • 幻读:A事务读取B事务的==新增==数据

    • 第一类更新丢失:A事务撤销时覆盖了B事务的提交

    • 第二类更新丢失:A事务覆盖B事务已经提交的数据

  6. JDBC默认情况下自动提交,即每条执行的SQL语句都对应一个事务,AutoCommit = TRUE

  7. Spring基于ThreadLocal解决有状态的Connetion的并发问题,事务同步管理器org.springframework.transaction.support.TransactionSynchronizationManager使用ThreadLocal为不同事务线程提供独立的资源副本

  8. Spring事务管理基于3个接口:TransactionDefinitionTransactionStatusPlatformTransactionManager

  9. Spring为不同持久化技术提供了从TransactionSynchronizationManager获取对应线程绑定资源的工具类,如DataSourceUtils.getConnection(DataSource dataSource)。模板类在内部通过工具类访问TransactionSynchronizationManager中的线程绑定资源

  10. Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中

  11. 使用<tx:annotation-driven transaction-manager="txManager">对标注@Transactional注解的bean进行加工处理,织入事务管理切面

  12. @Transactional注解的属性

    • 事务传播行为:propagation,默认PROPAGATION_REQUIRED,即如果当前没有事务,就新建一个事务;否则加入到当前事务

    • 事务隔离级别:isolation,默认ISOLATION_DEFAULT

    • 读写事务属性:readOnly

    • 超时时间:timeout

    • 回滚设置:rollbackForrollbackForClassNamenoRollbackFornoRollbackForClassName

  13. 在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中;如果在不同线程中,则工作在独立的事务中

  14. 特殊方法:

    • 注解不能被继承,所以业务接口中的@Transactional注解不会被业务实现类继承;方法处的注解会覆盖类定义处的注解

    • 对于基于接口动态代理的AOP事务,由于接口方法都是public的,实现类的实现方法必须是public的,同时不能使用static修饰符。因此,可以通过接口动态代理实施AOP增强、实现Spring事务的方法只能是publicpublic final

    • 基于CGLib动态代理实施AOP的时候,由于使用finalstaticprivate的方法不能被子类覆盖,相应的,这些方法不能实施AOP增强,实现事务

    • 不能被Spring进行AOP事务增强的方法不能启动事务,但是外层方法的事务上下文仍然可以传播到这些方法中

2. Spring中使用JDBC编程示例

  • 本地mysql建表

CREATE TABLE `t_user` (
  `user_id` varchar(256) NOT NULL,
  `user_name` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
  • springDAO.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:p="http://www.springframework.org/schema/p"
    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 ">

    <context:component-scan base-package="com.dao" />

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close"
        p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/sampledb"
        p:username="root"
        p:password="123123" />

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
        p:dataSource-ref="dataSource" />

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        p:dataSource-ref="dataSource" />
</beans>
  • User

package com.data;

public class User {

    private String userId;

    private String userName;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

}
  • BaseDAO

package com.dao;

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

public class BaseDAO {

    @Autowired
    protected JdbcTemplate jdbcTemplate;
}
  • UserDAO

package com.dao;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.data.User;
import com.mapper.UserRowMapper;

@Repository
public class UserDAO extends BaseDAO {

    private static final String SQL_GET_USER = "select * from t_user where " + "user_id = ?;";

    private static final String SQL_INSERT_USER = "insert into t_user values(?, ?);";

    private static final String SQL_CLEAN_USER = "delete from t_user where 1=1;";

    @Transactional
    public User getUserById(String userId) {
    return jdbcTemplate.queryForObject(SQL_GET_USER, new Object[]{userId}, new UserRowMapper());
    }

    @Transactional
    public int insertUser(User user) {
        return jdbcTemplate.update(SQL_INSERT_USER, user.getUserId(), user.getUserName());
    }

    @Transactional
    public int cleanUser() {
        return jdbcTemplate.update(SQL_CLEAN_USER);
    }
}
  • UserRowMapper

package com.dao;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

import com.data.User;

public class UserRowMapper implements RowMapper<User>{

    public User mapRow(ResultSet rs, int rowNumber) throws SQLException {
        User user = new User();
        user.setUserId(rs.getString("user_id"));
        user.setUserName(rs.getString("user_name"));
        return user;
    }
}
  • BaseTestCase

package com;

import org.junit.Assert;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/springDAO.xml"})
public class BaseTestCase extends Assert {

}
  • TestUserDAO

package com.dao;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.BaseTestCase;
import com.data.User;

public class TestUserDAO extends BaseTestCase{

    @Before
    @After
    public void clean() {
        dao.cleanUser();
    }

    @Autowired
    private UserDAO dao;

    @Test
    public void getUserById() {
        User user = new User();
        String id = "id";
        String name = "name";
        user.setUserId(id);
        user.setUserName(name);
        assertEquals(dao.insertUser(user), 1);

        user = dao.getUserById(id);
        assertEquals(user.getUserId(), id);
        assertEquals(user.getUserName(), name);
    }
}
要下载 Spring Framework 的官方文档 PDF,可以按照以下步骤进行操作: 1. 访问 Spring 官网:https://spring.io/projects/spring-framework[^1]。 2. 在页面上选择所需的框架版本。 3. 点击右侧的 **LEARN** 标签。 4. 点击 **Reference Doc.** 进入 HTML 格式的官方文档页面。 5. 在浏览器地址栏中的 HTML 路径后直接添加 `/pdf`,即可进入 PDF 下载页面。 例如,如果 HTML 文档的 URL 是 `https://docs.spring.io/spring-framework/docs/current/reference/html/`,则在地址栏中输入 `https://docs.spring.io/spring-framework/docs/current/reference/html/pdf/`,系统会自动跳转到 PDF 版本的下载页面。 ### 中文文档资源 对于希望使用中文阅读 Spring Framework 官方文档的用户,Spring 提供了部分中文翻译的内容。这些内容涵盖了从基础概念到高级特性的多个方面,包括但不限于: - **IoC 容器**:介绍了控制反转(Inversion of Control, IoC)的基本原理及其在 Spring 中的应用。 - **AOP**:面向切面编程(Aspect-Oriented Programming, AOP)的概念及其实现方式。 - **数据访问**:涉及 DAO 支持、JDBC、ORM 映射等内容。 - **Web 开发**:包括 Spring MVC 和 WebFlux 框架的相关介绍。 - **测试支持**:提供了对单元测试和集成测试的支持,如 TestContext 框架、Spring MVC 测试等[^2]。 ### 示例配置文件 下面是一个简单的 Spring 应用上下文配置文件示例,展示了如何通过 XML 配置来启用组件描功能,以便 Spring 自动检测并注册 Bean: ```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"> <!-- 自动--> <!-- 配置后会自动描 base-package 所标识包下的注解全部类 --> <context:component-scan base-package="com.zsjt"/> </beans> ``` 此配置文件启用了组件描,这意味着 Spring 会在指定的包路径下查找带有 `@Component` 注解的类,并将它们注册为 Spring 应用上下文中的 Bean。 ### 最新信息与教程 除了官方文档外,还有许多在线教程和社区资源可以帮助开发者更深入地了解 Spring Framework 的使用方法。这些资源通常包括详细的教程文章、视频课程以及实战项目案例,非常适合初学者和有经验的开发者学习和参考。此外,随着 Spring 生态系统的不断发展,新的模块和技术也在不断加入,确保开发者能够跟上技术发展的步伐。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值