zoukankan      html  css  js  c++  java
  • [Re] Spring-3(JdbcTemplate)

    Spring 提供了 JdbcTemplate 以便捷地操作 DB。

    1. CRUD 测试

    1.1 导包

    1.2 配置文件

    <!-- 
    DAO 层组件自动装配 JdbcTemplate:
        @Repository
        public class EmpDao {
            @Autowired
            JdbcTemplate jdbcTemplate;
        }
    -->
    <context:component-scan base-package="cn.edu.nuist"></context:component-scan>
    
    <!-- 引用外部属性文件;"classpath:" 固定写法,引入类路径下资源 -->
    <context:property-placeholder location="classpath:dbconfig.properties"/>
    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
    </bean>
    
    <!-- Spring 提供了一个类 JdbcTemplate,使用它来操作 DB -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    
    <!-- 配置一个具有 ‘具名参数’ 功能的 JdbcTemplate -->
    <bean id="namedParameterJdbcTemplate"
            class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    

    1.3 测试

    public class TestJDBC {
        ApplicationContext ioc = new 
                ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        JdbcTemplate jdbcTemplate = ioc.getBean(JdbcTemplate.class);
        NamedParameterJdbcTemplate namedParamJdbcTemplate = 
                ioc.getBean(NamedParameterJdbcTemplate.class);
    
        // 8. 创建 EmpDao,自动装配 JdbcTemplate 对象
        @Test
        public void testEmpDao() {
            EmpDao empDao = ioc.getBean(EmpDao.class);
            Employee emp = new Employee();
            emp.setEmpName("吴九");
            emp.setSalary(5000);
            empDao.saveEmp(emp);
            empDao.saveEmp(emp);
        }
    
        // 7. 以SqlParameterSource形式传入参数值
        public void testSqlParameterSource() {
            String sql = "INSERT INTO employees(emp_name, salary) VALUES(:empName, :salary)";
            Employee emp = new Employee();
            emp.setEmpName("崔八");
            emp.setSalary(5000);
            // SqlParameterSource BeanPropertySqlParameterSource
            int update = namedParamJdbcTemplate.update(sql
                    , new BeanPropertySqlParameterSource(emp));
            System.out.println(update);
        }
    
        /*
        6. 使用带有具名参数的 SQL 语句插入一条员工记录,并以 Map 形式传入参数值
            占位符参数:? 的顺序不能乱,传参的时候要注意
            具名参数:具有名字的参数,参数不是占位符了,而是一个变量名
                语法格式 [:参数名]
                Spring 有一个支持具名参数功能的JdbcTemplate: NamedParameterJdbcTemplate
         */
        public void insertWithMap() {
            String sql = "INSERT INTO employees(emp_name, salary) VALUES(:empName, :salary)";
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("empName", "田七");
            paramMap.put("salary", 5000);
            int update = namedParamJdbcTemplate.update(sql, paramMap);
            System.out.println(update);
        }
    
        // 5. 更新数据
        public void testUpdate() {
            String sql = "UPDATE employees SET salary = ? WHERE emp_id = ?";
            int update = jdbcTemplate.update(sql, 4000, 4);
            System.out.println(update);
        }
    
        // 4. 批量插入数据
        public void testBatchAdd() {
            String sql = "INSERT INTO employees(emp_name, salary) VALUES(?, ?)";
            // List<Object[]>
            // List.size: SQL 语句要执行的次数
            // Object[]: 每次执行要用的参数
            List<Object[]> batchArgs = new ArrayList<>();
            batchArgs.add(new Object[] {"张三", 3000});
            batchArgs.add(new Object[] {"李四", 3000});
            batchArgs.add(new Object[] {"王五", 3000});
            batchArgs.add(new Object[] {"赵六", 3000});
            int[] updates = jdbcTemplate.batchUpdate(sql, batchArgs);
            System.out.println(Arrays.toString(updates));
        }
    
        // 3. 查询单个数据
        public void queryMaxSalary() {
            String sql = "SELECT MAX(salary) FROM employees";
            int maxSalary = jdbcTemplate.queryForObject(sql, Integer.class);
            System.out.println(maxSalary);
        }
    
        /*
         * JavaBean 需要和 DB 中表的字段名一致,否则无法完成封装
         * JdbcTemplate 在方法级别进行了区分
         *  > 查询单个对象:template.queryForObject(),如果查询不到就会抛异常
         *  > 查询集合:template.query()
         */
    
        // 2. 查询多条记录,封装到 List
        public void queryMore() {
            String sql = "SELECT emp_id empId, emp_name empName, salary"
                    + " FROM employees WHERE salary > ?";
            // 封装 List
            List<Employee> emps = jdbcTemplate.query(sql
                    , new BeanPropertyRowMapper<>(Employee.class), 3000);
            System.out.println(emps);
        }
    
        // 1. 查询 1 条记录,封装到 JavaBean
        public void queryOne() {
            String sql = "SELECT emp_id empId, emp_name empName, salary"
                + " FROM employees WHERE emp_id = ?";
            Employee emp = jdbcTemplate.queryForObject(sql
                    , new BeanPropertyRowMapper<>(Employee.class), 40);
            System.out.println(emp);
        }
    }
    

    2. 声明式事务

    事务管理代码的固定模式作为一种横切关注点,可以通过 AOP 方法模块化,进而借助 Spring AOP 框架实现声明式事务管理。

    这个事务管理器就可以在目标方法运行前后进行事务控制(事务切面)。我们目前使用 DataSourceTransactionManager 即可。

    2.1 配置文件

    <!-- 导入外部配置文件 -->
    <context:property-placeholder location="classpath:dbconfig.properties"/>
    
    <!-- 配数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
        <property name="minPoolSize" value="${jdbc.minPoolSize}"></property>
    </bean>
    
    <!-- 事务控制-->
    <!-- 1. 配置事务管理器让其进行事务管理 -->
    <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 控制住数据源 (控制事务实际就是控制住Connection) -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 2. 开启基于注解的事务控制模式(依赖 tx 名称空间), 默认 transactionManager -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    <!-- 3. 给事务方法加 @Transactional → 环绕通知Around -->
    

    2.2 @Transactional

    2.2.1 propagation

    事务的传播行为(事务的传播 + 事务的行为),如果有多个事务进行嵌套运行,子事务是否和大事务共用一个事务(使用同一条连接)。

    • 如果是 REQUIRED,则子事务的属性都是继承自大事务。
    • REQUIRED 是将之前事务用的 Connection 传递过来
    • REQUIRES_NEW 直接使用新的 Connection

    2.2.2 isolation

    事务的隔离级别。

    • READ_UNCOMMITTED
    • READ_COMMITTED
    • REPEATABLE_READ
    • SERIALIZABLE

    2.2.3 timeout

    • 超时属性
    • 事务超出指定时长(秒为单位) 后自动终止并回滚

    2.2.4 readOnly

    • 默认 false
    • 可以进行事务优化
    • 能加快查询速度,不用管事务那堆操作了
    • 如果设置为 true 后,做非查询操作,会抛异常

    2.2.5 rollback 相关

    • 异常分类
      • 运行时异常(非检查异常):可以不用处理,默认都回滚
      • 编译时异常(检查异常):默认不回滚
    • 回滚相关属性
      • rollbackFor:出现哪些异常,事务可以不回滚
      • rollbackForClassName
      • noRollbackFor:原来不回滚的异常,指定让其回滚
      • noRollbackForClassName

    3. 基于 XML 配置的事务

    1. 依赖 tx、aop 名称空间
    2. <aop:pointcut> 切入点表达式
    3. <tx:advice> 事务通知,类比注解式中的切面类 (事务切面按照切入点表达式去切入事务方法)
    4. <aop:advisor> 关联 [切入点表达式] 和 [事务通知]

    <aop:config>
        <!-- 切入点表达式 -->
        <aop:pointcut id="txPoint" expression="execution(* cn.edu.nuist.service.*.*(..))"/>
        <!-- 事务建议:关联 [切入点表达式] 和 [事务通知] -->
        <aop:advisor pointcut-ref="txPoint" advice-ref="myAdvice"/>
    </aop:config>
    
    <!-- 事务通知 // 关联 [事务管理器] -->
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <!-- 事务属性 -->
        <tx:attributes>
            <!-- 指明哪些方法是事务方法:
            切入点表达式只是说,事务管理器要切入这些方法,至于方法的详细
            配置(传播行为、隔离级别、回滚异常 ...),还需要使用 tx:method
            -->
            <tx:method name="*"/>
            <tx:method name="checkout" propagation="REQUIRED" timeout="-1"/>
            <tx:method name="get*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 都用;重要的用配置,不重要的用注解 -->
    
  • 相关阅读:
    FTPClient FTPFile 找不到符号
    1.4 Spring 依赖注入(DI)和控制反转(IOC)详解
    1.3使用marven Spring项目快速搭建
    1.1Spring历史发展和模块定义
    @Component、@Service、@Controller、@Rrepository说明
    打板炒股方法
    性能测试Jmeter扩展学习-添加自定义函数
    性能测试day07_性能瓶颈和分析
    性能测试day06_需求设计的学习(性能重中之重,思维方向永远重于工具)
    性能监控扩展篇(grafana + influxdb + telegraf)
  • 原文地址:https://www.cnblogs.com/liujiaqi1101/p/13672349.html
Copyright © 2011-2022 走看看