zoukankan      html  css  js  c++  java
  • (IV)JdbcTemplate

    一、概述

      为了使JDBC更加易于使用,Spring在JDBC API上定义了一个抽象层,以此建立一个JDBC存取框架。

      作为Spring JDBC框架的核心,JDBC模板的设计目的是为不同类型的JDBC操作提供模板方法,通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低

      可以将Spring的JdbcTemplate看作是一个小型的轻量级持久化层框架,和我们之前使用过的DBUtils风格非常接近。

    二、环境准备

      1、导入 jar 包

        ① IOC 容器所需要的 jar 包

    commons-logging-1.1.1.jar

    spring-beans-4.0.0.RELEASE.jar

    spring-context-4.0.0.RELEASE.jar

    spring-core-4.0.0.RELEASE.jar

    spring-expression-4.0.0.RELEASE.jar

        ② JdbcTemplate 所需要的 jar 包

    spring-jdbc-4.0.0.RELEASE.jar

    spring-orm-4.0.0.RELEASE.jar

    spring-tx-4.0.0.RELEASE.jar

        ③ 数据库驱动和数据源

    c3p0-0.9.5.jar

    mysql-connector-java-5.1.7-bin.jar

      2、连接数据库基本信息属性文件

    jdbc_username=root
    jdbc_password=root
    jdbc_url=jdbc:mysql://localhost:3306/jdbc_template
    jdbc_driverClassName=com.mysql.jdbc.Driver
    
    initialPoolSize=30
    minPoolSize=10
    maxPoolSize=100
    acquireIncrement=5
    maxStatements=1000
    maxStatementsPerConnection=10

      3、在Spring配置文件中配置相关的bean

        ① 数据源对象

        <!--引入外部配置文件-->
        <context:property-placeholder location="db.properties"></context:property-placeholder>
    
        <!--
            ${} :取出配置文件总的值
            #{} :Spring 表达式的值
        -->
        <!-- 测试数据源 -->
        <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>

        ② JdbcTemplate 对象

        <!--  Spring 提供了一个类 JdbcTemplate,我们用它操作数据库,导入 Spring 的数据库模块  -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

    三、持久化操作

      1、增删改操作

        方法:

    JdbcTemplate.update(sql)            //执行 SQL 语句
    JdbcTemplate.update(sql,Object... args)  //执行可以赋值参数的SQL语句
    

      

        案例:

        @Test
         public void testInsert() {
             //插入
             //jdbcTemplate.update("insert into emp  values(null,'张三',23,'男')");
             String sql = "insert into emp  values(null,?,?,?)";
             jdbcTemplate.update(sql, "李四",18,"女");
             
         }
         
         @Test
         public void testUpdate() {
             //更新
             //jdbcTemplate.update("update emp set  ename='王五',age=17,sex='男' where eid=1");
             String sql = "update emp set  ename=?,age=?,sex=? where eid=?";
             jdbcTemplate.update(sql, "张三",22,"女",1);
         }
         
         @Test
         public void testDelete() {
             //删除
             //jdbcTemplate.update("delete from emp where  eid = 3");
             String sql = "delete from emp where eid=?";
             jdbcTemplate.update(sql, 3);
         }

      2、批量增删改操作

        方法:

    JdbcTemplate.batchUpdate(sql, List<Object[]>)
        Object[]封装了SQL语句每一次执行时所需要的参数
        List集合封装了SQL语句多次执行时的所有参数
    

      

        案例:

        @Test
         public void testBatchInsert() {
             //批量添加
             String sql = "insert into emp  values(null,?,?,?)";
             List<Object[]> list = new ArrayList<>();
             list.add(new Object[] {"a1",1,"男"});
             list.add(new Object[] {"a2",2,"女"});
             list.add(new Object[] {"a3",3,"女"});
             list.add(new Object[] {"a4",4,"男"});
             jdbcTemplate.batchUpdate(sql, list);
         }
         
         @Test
         public void testBatchUpdate() {
             //批量更新
             String sql = "update emp set  ename=?,age=?,sex=? where eid=?";
             List<Object[]> list = new ArrayList<>();
             list.add(new Object[] {"b1",11,"男",4});
             list.add(new Object[] {"b2",12,"男",5});
             jdbcTemplate.batchUpdate(sql, list);
         }
         
         @Test
         public void testBatchDelete() {
             //批量删除
             String sql = "delete from emp where eid = ?";
             List<Object[]> list = new ArrayList<>();
             list.add(new Object[] {6});
             list.add(new Object[] {7});
             jdbcTemplate.batchUpdate(sql, list);
         }

      3、查询单行

        方法:

    jdbcTemplate.queryForObject(sql, RowMapper)用来获取单条数据
    jdbcTemplate.queryForObject(sql, new  Object[]{}, RowMapper<T>)用来获取单条数据
    jdbcTemplate.queryForObject(sql, RowMapper<T>,  Object... args)用来获取单条数据
    

      

        

        案例:

        @Test
         public void testQueryForObject() {
             //jdbcTemplate.queryForObject(sql,  RowMapper)用来获取单条数据
             //jdbcTemplate.queryForObject(sql, new  Object[]{} RowMapper)用来获取单条数据
             //jdbcTemplate.queryForObject(sql, RowMapper,  Object... args)用来获取单条数据
             
             RowMapper<Emp> rowMapper = new  BeanPropertyRowMapper<>(Emp.class); //将列名(字段名或字段名的别名)与属性名进行映射
             
             String sql = "select eid,ename,age,sex from  emp where eid=1";
             Emp emp = jdbcTemplate.queryForObject(sql,  rowMapper);
             System.out.println(emp);
             
             String sql2 = "select eid,ename,age,sex from  emp where eid=?";
             Emp emp2 = jdbcTemplate.queryForObject(sql2,  new Object[] {4}, rowMapper);
             System.out.println(emp2);
             
             String sql3 = "select eid,ename,age,sex from  emp where eid=?";
             Emp emp3 = jdbcTemplate.queryForObject(sql3,  rowMapper, 5);
             System.out.println(emp3);
         }

      4、查询多行

        方法:

    jdbcTemplate.query(String sql,  RowMapper<T>);
    jdbcTemplate.query(String sql, Object[]  args, RowMapper<T>);
    jdbcTemplate.query(String sql, RowMapper<T>,  Object... args);

          RowMapper对象依然可以使用BeanPropertyRowMapper

        案例:

       @Test
         public void testQuery() {
             //查询多行记录
             //jdbcTemplate.query(String sql,  RowMapper<T>);
             //jdbcTemplate.query(String sql, Object[]  args, RowMapper<T>);
             //jdbcTemplate.query(String sql, RowMapper<T>,  Object... args);
             RowMapper<Emp> rowMapper = new  BeanPropertyRowMapper<>(Emp.class);
             
             String sql = "select eid,ename,age,sex from  emp";
             List<Emp> list = jdbcTemplate.query(sql,  rowMapper);
             for (Emp emp : list) {
                  System.out.println(emp);
             }
             System.out.println("-----------");
             String sql2 = "select eid,ename,age,sex from  emp where eid > ?";
             List<Emp> list2 = jdbcTemplate.query(sql2, new  Object[] {2}, rowMapper);
             for (Emp emp : list2) {
                  System.out.println(emp);
             }
             System.out.println("-----------");
             String sql3 = "select eid,ename,age,sex from  emp where eid > ?";
             List<Emp> list3 = jdbcTemplate.query(sql3,  rowMapper, 2);
             for (Emp emp : list3) {
                  System.out.println(emp);
             }
         }

      5、查询单个值

        方法:

    jdbcTemplate.queryForObject(sql, Class, Object... args);
    jdbcTemplate.queryForObject(sql,  requiredType);
    jdbcTemplate.queryForObject(sql,  requiredType, args);

        案例:

         @Test
         public void testQueryForSingleValue() {
             //jdbcTemplate.queryForObject(sql,  requiredType);
             //jdbcTemplate.queryForObject(sql,  requiredType, args);
             String sql = "select count(*) from emp";
             Integer count =  jdbcTemplate.queryForObject(sql, Integer.class);
             System.out.println(count);
             
             String sql2 = "select count(*) from emp where  eid > ?";
             Integer count2 =  jdbcTemplate.queryForObject(sql2, Integer.class, 2);
             System.out.println(count2);
         }

    四、使用具名参数的JdbcTemplate

      1、关于具名参数

        在Hibernate的HQL查询中我们体验过具名参数的使用,相对于基于位置的参数,具名参数具有更好的可维护性,在SQL语句中参数较多时可以考虑使用具名参数。

        在Spring中可以通过NamedParameterJdbcTemplate类的对象使用带有具名参数的SQL语句

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

        <!-- 配置一个具有 具名参数 供的 JdbcTemplate NamedParameterJdbcTemplate-->
        <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
            <!--使用构造器注入一个数据源-->
            <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
        </bean>

      3、具名参数在SQL 语句中的格式

    INSERT INTO employee(emp_name, salary) VALUES(:empName, :salary)
    

      

      4、具名参数传入

        ① 通过 Map 对象传入

        @Test
        public void test8() throws Exception {
            String sql = "INSERT INTO employee(emp_name, salary) VALUES(:empName, :salary)";
    
            //将所有具名参数的值放在 map 中
            HashMap<String, Object> paramMap = new HashMap<>();
            paramMap.put("empName", "田七");
            paramMap.put("salary", "9987.89");
    
            namedParameterJdbcTemplate.update(sql, paramMap);
        }

          Map 的键是参数名,值是参数值;

        ② 通过 SqlParameterSource 对象传入

          

           代码示例:

        @Test
        public void test() throws Exception {
            String sql = "INSERT INTO employee(emp_name, salary) VALUES(:empName, :salary)";
    
            Employee employee = new Employee();
            employee.setEmpName("哈哈");
            employee.setSalary(998.98);
    
            int update = namedParameterJdbcTemplate.update(sql, new BeanPropertySqlParameterSource(employee));
            System.out.println("update = " + update);
        }

        bean 的属性名要与具名参数一致。

    五、使用JdbcTemplate实现Dao

      通过 IOC 容器自动注入:

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

        代码示例:

    @Repository
    public class EmpDao {
         
         @Autowired
         private JdbcTemplate jdbcTemplate;
         
         public Emp getEmp(Integer id) {
             
         }
    }

    六、注意

      在给 SQL 赋值时,如果使用PreparedStatement给通配符赋值时,如果给赋值的是字符串类型,那它就会默认给所赋的值添加一对单引号。

      示例1:

         @Test
         public void testDel() {
             //错误的,不能通过 PreparedStatement 赋值,在批量删除,批量修改时
             //调用PreparedStatement中 setString()方法时,因为字符串传到SQL语句中去自动加单引号的,所以不能使用通配符赋值
             String sql = "delete from emp where eid in  (?)";
             String eids = "9,10,11";
             jdbcTemplate.update(sql, eids);  //delete from  emp where eid in ('9,10,11'); //只删除eid为9的记录
             
             //修改,使用拼接,不适用通配符赋值
             String sql2 = "delete from emp where eid in ("  + eids + ")";
             jdbcTemplate.update(sql2);
         }

      示例2:

         @Test
         public void testSelect() {
             //会使用PreparedStatement的 setString() 方法,会有单引号的拼接问题
             String sql = "select * from emp where ename  like '%?%'";
             //如果问号处传入的 是 字符串 "a",SQL 语句就变成 :select * from emp where ename like '%'a'%' ,发生错误!!!
             
             
             //修改,使用concat() 函数
             String sql2 = "select * from emp where ename  like concat('%', ?, '%')";
             jdbcTemplate.update(sql2, "a");  // SQL 语句:select * from emp where ename like '%a%'
         }
  • 相关阅读:
    linux 操作 I/O 端口
    linux I/O 端口分配
    大数问题:求n的阶乘
    POJ 2586 Y2K Accounting Bug
    每天一点儿Java--ComboBox
    android的一些控件
    解决Linux(ubuntu),windows双系统重装后恢复开机选单
    Mysql数据备份与恢复
    log4net 存储到oracle 调试 Could not load type [log4net.Appender.OracleAppender]
    POJ 2533 Longest Ordered Subsequence
  • 原文地址:https://www.cnblogs.com/niujifei/p/15483949.html
Copyright © 2011-2022 走看看