4. 声明式事务

1. JdbcTemplate

Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作,可以方便对数据库的增删改查

1.1 对JdbcTemplate的准备工作

(1) 加入依赖

<dependencies>
        <!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- Spring 持久化层支持jar包 -->
        <!-- Spring 在执行持久化层操作、与持久化层(相当于jdbc的dao层)技术进行整合过程中,需要使用orm、jdbc、tx三个
        jar包 -->
        <!-- 导入 orm 包就可以通过 Maven 的依赖传递性把其他两个也导入 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- Spring 测试相关 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- 数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>
    </dependencies>

(2) 创建\(jdbc.property\)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=root

  不创建也可以,但是这样在spring配置文件中,这些就是写死的

(3) 配置\(Spring\)的配置文件

    <!-- 导入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties" />
    <!-- 配置数据源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!-- 配置 JdbcTemplate,交给ioc容器管理 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 装配数据源 -->
        <property name="dataSource" ref="druidDataSource"/>
    </bean>

  这里的逻辑是要使用\(JdbcTemplate\)需要使用数据源,我们则需要将数据源引入到项目中,故引入了\(druid\)数据池

  • 延伸知识:什么是classpath
      如果是纯\(java\)项目,则没有加前缀\(classpath\)的必要,但如果是\(web\)项目,则需要前缀指定类路径。
      此po主讲得十分详细大佬的讲解,这里加点自己的理解。
      开发时期的\(web\)项目路径如下图,但是在我们把项目打包后,是不存在\(webapp\)的路径的,我们的\(java\)\(resource\)路径都被放在\(WEB-INF\)路径里
    image

  打包后的\(web\)项目路径,\(java\)\(resource\)都被(编译)打包到了生产包的\(WEB-INF/classes/\)目录下;而原来\(WEB-INF\)下面的\(views\)\(web.xml\)则仍然还是在\(WEB-INF\)下面。同时由\(maven\)引入的依赖都被放入到了\(WEB-INF/lib/\)下面。最后,编译后的\(class\)文件和资源文件都放在了\(classes\)目录下。
image
image
  那么classPath是从哪里开始呢?就是指\(WEB-INF/classes/\)这个目录的路径.每当我们使用这个前缀时,只能指定一个文件的路径,如果指定多个文件的路径需要使用\(classpath*\)
image
  最后我们说的\(web\)根路径到底在哪?也就是从\(ssmProject\)开始的路径(当前目录是META-INF和WEB-INF)

1.2 Spring整合junit

  在以往测试类中,我们往往需要每个方法都执行以下两行代码:

	ApplicationContext ioc = new ClassPathXmlApplicationContext("spring-jdbcTemplate.xml");
	ioc.getBean();

  如果方法较多就比较麻烦,但是与Spring整合后就可以自动获取ioc容器,我们只需要配置\(@RunWith\)\(@ContextConfiguration\)两个注解即可。

//@RunWith:设置测试类的运行环境:指定测试类在Spring环境下执行,此时就可以通过注入的方式
//直接获取ioc容器中的bean
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration:设置spring的配置文件
@ContextConfiguration("classpath:spring-jdbcTemplate.xml")
public class JdbcTemplateTest {
    //查找配置文件对应的类
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Test
    public void testInsert(){
        String sql ="Insert into t_user values(null,?,?,?,?,?)";
        jdbcTemplate.update(sql,"tom","tom",23,"男","18912@163.com");
    }
}

  这里注意如果不加\(classpath:\)就会报错,\(@ContextConfiguration\)默认的是读取classes文件夹下的文件,测试了在路径前加/也可以正常运行。

1.3 jdbcTemplate查询

(1) 查询一条数据返回实体类对象

public void testgetUserById(){
        String sql = "select * from t_user where id = ?";
        /*
        String sql:查询的sql语句
        RowMapper<T> rowMapper:查询出来的数据与实体类的映射关系,这里一般使用的BeanPropertyRowMapper
                               它能将查询的字段与属性进行映射,默认字段名与属性一致就可以赋值
        @Nullable Object... args:参数列表
         */
        User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), 1);
        System.out.println(user);
    }

(2) 查询多条数据为一个list集合

public void testSelectList(){
        String sql = "select * from t_user";
        /*
        String sql:sql语句
        RowMapper<T> rowMapper:映射关系
         */
        List<User> users = jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(User.class));
        System.out.println(users);
    }

(3) 查询单行单列的值

public void selectCount(){
        String sql = "select count(id) from t_user";
        /*
        String sql:
        Class<T> requiredType:查询出来的数据要转化为什么类型
		如果有参数可以直接在方法的参数后加
         */
        int count = jdbcTemplate.queryForObject(sql, Integer.class);
        System.out.println("用户一共"+count+"人");
    }

2. 声明式事务概念

2.1 编程式事务

  事务功能的相关操作全部通过自己编写代码来实现:

Connection conn = ...;
try {
// 开启事务:关闭事务的自动提交
conn.setAutoCommit(false);
// 核心操作
// 提交事务
conn.commit();
}catch(Exception e){
// 回滚事务
conn.rollBack();
}

编程式的实现方式存在缺陷:

  • 细节没有被屏蔽:具体操作过程中,所有细节都需要程序员自己来完成,比较繁琐。
  • 代码复用性不高:如果没有有效抽取出来,每次实现功能都需要自己编写代码,代码就没有得到复用。(面向对象的思想是无法抽取出来的)
posted @ 2022-11-11 08:47  acmloser  阅读(13)  评论(0编辑  收藏  举报