• 第七章、JdbcTemplate


    概述

      为了使JDBC更加易于使用,Spring在JDBC API上定义了一个抽象层,以此建立一个JDBC存取框架。 作为Spring JDBC框架的核心,JDBC模板的设计目的是为不同类型的JDBC操作提供模板方法,通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低。 可以将Spring的JdbcTemplate看作是一个小型的轻量级持久化层框架,和我们之前使用过的DBUtils风格非常接近。

    一、环境/数据准备

          <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.2.2.RELEASE</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.11</version>
            </dependency>
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.5.2</version>
            </dependency>
    •  数据脚本
    CREATE DATABASE db1022;
    USE db1022;
    CREATE TABLE book (
    isbn VARCHAR (50) PRIMARY KEY COMMENT '书号',
    book_name VARCHAR (100) COMMENT '书名',
    price INT COMMENT '价格'
    ) ;
    
    CREATE TABLE book_stock (
    isbn VARCHAR (50) PRIMARY KEY COMMENT '书号',
    stock INT
    ) ;
    
    CREATE TABLE account (
    username VARCHAR (50) PRIMARY KEY COMMENT '用户名',
    balance INT COMMENT '用户余额'
    ) ;
    
    INSERT INTO account (`username`,`balance`) VALUES ('Tom',300);
    INSERT INTO account (`username`,`balance`) VALUES ('Jerry',400);
    
    INSERT INTO book (`isbn`,`book_name`,`price`) VALUES ('ISBN-001','book01',100);
    INSERT INTO book (`isbn`,`book_name`,`price`) VALUES ('ISBN-002','book02',200);
    
    
    INSERT INTO book_stock (`isbn`,`stock`) VALUES ('ISBN-001',10);
    INSERT INTO book_stock (`isbn`,`stock`) VALUES ('ISBN-002',20);

    二、创建连接数据库基本信息属性文件

    • 创建 jdbc.properties
    user=root
    password=root
    jdbcUrl=jdbc:mysql:///db1022?useSSL=false&serverTimezone=UTC
    driverClass=com.mysql.jdbc.Driver
    
    initialPoolSize=30
    minPoolSize=10
    maxPoolSize=100
    acquireIncrement=5
    maxStatements=1000
    maxStatementsPerConnection=10
    •  application_jdbcTemplate.xml
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${user}"/>
        <property name="password" value="${password}"/>
        <property name="jdbcUrl" value="${jdbcUrl}"/>
        <property name="driverClass" value="${driverClass}"/>
        <property name="initialPoolSize" value="${initialPoolSize}"/>
        <property name="minPoolSize" value="${minPoolSize}"/>
        <property name="maxPoolSize" value="${maxPoolSize}"/>
        <property name="acquireIncrement" value="${acquireIncrement}"/>
        <property name="maxStatements" value="${maxStatements}"/>
        <property name="maxStatementsPerConnection" value="${maxStatementsPerConnection}"/>
    </bean>
    
    <bean id="template"  class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    三、JdbcTemplate的增、删、改、查

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    @ToString
    public class Book {
        private String book_name;
        private String price;
    }
    • 测试类
    public class JDBCTemplate_Test {
    
        private ApplicationContext ctx = null;
        private JdbcTemplate jdbcTemplate = null;
    
        {
            ctx = new ClassPathXmlApplicationContext("application_jdbcTemplate.xml");
            jdbcTemplate = (JdbcTemplate) ctx.getBean("template");
        }
    
    
        /**
         * 执行 INSERT
         */
        @Test
        public void testInsert() {
            String sql = "INSERT INTO book (`isbn`,`book_name`,`price`) VALUES (?,?,?);";
            jdbcTemplate.update(sql, "ISBN", "ISBN", 100);
        }
    
        /**
         * 执行UPDATE
         */
        @Test
        public void testUpdate() {
            String sql = "UPDATE book SET book_name = ? WHERE price = ?";
            jdbcTemplate.update(sql,"book01",100);
        }
    
        /**
         * 执行 DELETE
         */
        @Test
        public void testDelete() {
            String sql = "DELETE from book WHERE book_name = ?";
            jdbcTemplate.update(sql, "book01");
        }
    
        /**
         * 测试批量更新操作 最后一个参数是 Object[] 的 List 类型:因为修改一条记录需要一个 Object 数组,修改多条记录就需要一个
         * List 来存放多个数组。
         */
        @Test
        public void testBatchUpdate() {
            String sql = "INSERT INTO book(isbn, book_name, price) VALUES(?, ?, ?)";
            List<Object[]> batchArgs = new ArrayList<>();
            batchArgs.add(new Object[] { "ISBN-006", "book06", "600" });
            batchArgs.add(new Object[] { "ISBN-007", "book07", "700" });
            batchArgs.add(new Object[] { "ISBN-008", "book08", "800" });
            batchArgs.add(new Object[] { "ISBN-009", "book09", "900" });
    
            jdbcTemplate.batchUpdate(sql, batchArgs);
        }
    
        /**
         * 从数据库中获取一条记录,实际得到对应的一个对象 注意:不是调用 queryForObject(String sql,Class<Employee> requiredType, Object... args) 方法!
         * 而需要调用queryForObject(String sql, RowMapper<Employee> rowMapper, Object... args)
         * 1、其中的 RowMapper 指定如何去映射结果集的行,常用的实现类为 BeanPropertyRowMapper
         * 2、使用SQL中的列的别名完成列名和类的属性名的映射,例如 last_name lastName
         * 3、不支持级联属性。 JdbcTemplate只能作为一个 JDBC 的小工具, 而不是 ORM 框架
         */
        @Test
        public void testQueryForObject() {
            String sql = "SELECT * FROM book WHERE isbn=?";
            RowMapper<Book> rowMapper = new BeanPropertyRowMapper<>(Book.class);
            //在将数据装入对象时需要调用set方法。
            Book book = jdbcTemplate.queryForObject(sql, rowMapper, "ISBN-003");
            System.out.println(book);
        }
    
        /**
         * 一次查询多个对象
         * 注意:调用的不是 queryForList 方法
         */
        @Test
        public void testQueryForList() {
            String sql = "SELECT * FROM book WHERE isbn like ?";
             RowMapper<Book> rowMapper = new BeanPropertyRowMapper<>(Book.class);
             List<Book> bookList = jdbcTemplate.query(sql, rowMapper, "%ISBN%");
            if (!CollectionUtils.isEmpty(bookList)) {
                bookList.forEach(user -> {
                    System.out.println(user);
                });
            }
        }
    
        /**
         * 获取单个列的值或做统计查询
         * 使用 queryForObject(String sql, Class<Long> requiredType)
         */
        @Test
        public void testQueryForCount() {
            String sql = "SELECT count(isbn) FROM book";
            long count = jdbcTemplate.queryForObject(sql, Long.class);
            System.out.println(count);
        }
    }

    四、使用具名参数的NamedParameterJdbcTemplate

    关于具名参数

    String sql = "SELECT * FROM book WHERE isbn=?";
    由上面可以看出使用?作为展位符,在填充参数的时候要考虑问号的顺序。具名参数很好的解决了这个问题,是我们在填充参数时不用考虑参数顺序
    在Spring中可以通过NamedParameterJdbcTemplate类的对象使用带有具名参数的SQL语句。

    4.1、通过IOC容器创建NamedParameterJdbcTemplate对象

         <!-- 配置可以使用具名参数的JDBCTemplate类对象 -->
            <bean id="namedTemplate"  class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
            <!-- 没有无参构造器,必须传入数据源或JdbcTemplate对象 -->
            <constructor-arg ref="dataSource"/>

    4.2、具名参数传入方式有两种

    (1)、通过Map对象传入

    NamedParameterJdbcTemplate.update(String sql, Map<String, ?> map)
    Map的键是参数名,值是参数值

    (2)、通过SqlParameterSource对象传入

    public class NamedParameterJdbcTemplate_Test {
        private ApplicationContext ctx = null;
        private NamedParameterJdbcTemplate template = null;
    
        {
            ctx = new ClassPathXmlApplicationContext("application_jdbcTemplate.xml");
            template = (NamedParameterJdbcTemplate) ctx.getBean("namedTemplate");
        }
    
        /**
         * 通过Map对象传入
         */
        @Test
        public void test_Method01(){
            //:p、:bn 具名参数名字随便起,冒号+名字
            String sql = "UPDATE book SET price = :p WHERE book_name = :bn";
            Map<String, Object> paramMap = new HashMap<String, Object>();
            paramMap.put("bn","book01");
            paramMap.put("p","1000");
            System.out.println(template.update(sql, paramMap));
        }
    
        /**
         * 通过SqlParameterSource对象传入
         */
        @Test
        public void test_Method02(){
            //模拟Service曾直接传递给Dao曾一个具体的对象。
            String sql = "UPDATE book SET price = :price WHERE book_name = :book_name";
            Book book = new Book("book01","10000");
            //此时剧名参数名称必须好对象的属性名称保持一致
            SqlParameterSource sqlParameterSource = new BeanPropertySqlParameterSource(book);
            System.out.println(template.update(sql, sqlParameterSource));
        }
    }

    五、使用JdbcTemplate实现Dao

    通过IOC容器自动注入:JdbcTemplate类是线程安全的,所以可以在IOC容器中声明它的单个实例,并将这个实例注入到所有的Dao实例中。

    @Repository
    public class EmployeeDao {
        
        @Autowired
        private JdbcTemplate jdbcTemplate;
        
        public Employee get(Integer id){
            //
        }
    }
  • 相关阅读:
    20180925-6 四则运算试题生成
    20180925-7 规格说明书-吉林市2日游
    20180925-5 代码规范,结对要求
    20180925-2 功能测试
    20180918-2 每周例行报告
    互评Alpha版本
    2017软工 — 每周PSP
    王者荣耀交流协会 — Alpha阶段中间产物
    王者荣耀交流协会第四次Scrum立会
    2017秋软工 —— 本周PSP
  • 原文地址:https://www.cnblogs.com/jdy1022/p/13678829.html
Copyright © 2020-2023  润新知