• jdbcTemplate学习(一)


    概述

    Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式。

           JdbcTemplate类通过模板设计模式帮助我们消除了冗长的代码,只做需要做的事情(即可变部分),并且帮我们做哪些固定部分,如连接的创建及关闭。

           JdbcTemplate类对可变部分采用回调接口方式实现,如ConnectionCallback通过回调接口返回给用户一个连接,从而可以使用该连接做任何事情、StatementCallback通过回调接口返回给用户一个Statement,从而可以使用该Statement做任何事情等等,还有其他一些回调接口

    Spring除了提供JdbcTemplate核心类,还提供了基于JdbcTemplate实现的NamedParameterJdbcTemplate类用于支持命名参数绑定、 SimpleJdbcTemplate类用于支持Java5+的可变参数及自动装箱拆箱等特性。

    JdbcTemplate类支持的回调类:

    • 预编译语句及存储过程创建回调:用于根据JdbcTemplate提供的连接创建相应的语句;

    PreparedStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的PreparedStatement;

    CallableStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的CallableStatement;

    • 预编译语句设值回调:用于给预编译语句相应参数设值;

             PreparedStatementSetter:通过回调获取JdbcTemplate提供的PreparedStatement,由用户来对相应的预编译语句相应参数设值;

             BatchPreparedStatementSetter:;类似于PreparedStatementSetter,但用于批处理,需要指定批处理大小;

    • 自定义功能回调:提供给用户一个扩展点,用户可以在指定类型的扩展点执行任何数量需要的操作;

             ConnectionCallback:通过回调获取JdbcTemplate提供的Connection,用户可在该Connection执行任何数量的操作;

             StatementCallback:通过回调获取JdbcTemplate提供的Statement,用户可以在该Statement执行任何数量的操作;

             PreparedStatementCallback:通过回调获取JdbcTemplate提供的PreparedStatement,用户可以在该PreparedStatement执行任何数量的操作;

             CallableStatementCallback:通过回调获取JdbcTemplate提供的CallableStatement,用户可以在该CallableStatement执行任何数量的操作;

    • 结果集处理回调:通过回调处理ResultSet或将ResultSet转换为需要的形式;

             RowMapper:用于将结果集每行数据转换为需要的类型,用户需实现方法mapRow(ResultSet rs, int rowNum)来完成将每行数据转换为相应的类型。

             RowCallbackHandler:用于处理ResultSet的每一行结果,用户需实现方法processRow(ResultSet rs)来完成处理,在该回调方法中无需执行rs.next(),该操作由JdbcTemplate来执行,用户只需按行获取数据然后处理即可。

             ResultSetExtractor:用于结果集数据提取,用户需实现方法extractData(ResultSet rs)来处理结果集,用户必须处理整个结果集;

    下面详细讲解jdbcTmeplate的CRUD操作:

    (一)增加、删除、修改操作:

    1)增加、更新、删除(一条sql语句)(sql固定,不需要参数):

        (a) int update(final String sql)

          其中sql参数为需要传入的插入sql语句。

        (b)int update(PreparedStatementCreator psc)

        public void test() {
            jdbcTemplate.update(new PreparedStatementCreator() {
                
                @Override
                public PreparedStatement createPreparedStatement(Connection conn)
                        throws SQLException {
                    return conn.prepareStatement("insert into test(name) values('name1')");   
                }
            });
        }

         (c)如果需要返回新插入数据的主键,采用如下方法(使用KeyHolder keyholder=new GeneratedKeyHolder();获得主键,jdbcTemplate和NamedParameterJdbcTemplate都可以通过此方法获得主键):

           int update(PreparedStatementCreator psc, final KeyHolder generatedKeyHolder)

    public void test() {
            KeyHolder keyHolder = new GeneratedKeyHolder(); 
            jdbcTemplate.update(new PreparedStatementCreator() {
                
                @Override
                public PreparedStatement createPreparedStatement(Connection conn)
                        throws SQLException {
                    
                    return conn.prepareStatement("insert into test(name) values('name1')");  
                     
                }
            },keyHolder);
            int i = keyHolder.getKey().intValue();//这就是刚插入的数据的主键
        }

    2)增加、更新、删除(一条sql语句)(sql需要注入参数填充‘?’):

      (a)int update(String sql, PreparedStatementSetter pss)

    public void test() {
            String sql = "insert into test(name) values (?)";
            //返回的是更新的行数
            int count = jdbcTemplate.update(sql, new PreparedStatementSetter(){
    
                @Override
                public void setValues(PreparedStatement pstmt)
                        throws SQLException {
                    pstmt.setObject(1, "name4"); 
                }
            });
        }

          (b)int update(String sql, Object[] args, int[] argTypes)

    其中参数含义:   sql:预处理sql语句; args:sql需要注入的参数; argTypes:需要注入的sql参数的JDBC类型(java.sql.Types中来获取类型的常量);

        public void test() {
            String sql = "insert into test(name,age,create_date) values (?,?,?)";
            Date now = new Date(System.currentTimeMillis());
            //返回的是更新的行数
            int count = jdbcTemplate.update(sql, new Object[]{"小明",14,now}, new int[]{Types.VARCHAR,Types.INTEGER,Types.DATE});
        }

         (c)int update(String sql, Object... args)

    其实内部还是调用方法a实现的,JdbcTemplate提供这种更简单的方式“update(String sql, Object... args)”来实现设值,所以只要当使用该种方式不满足需求时才应使用PreparedStatementSetter(上面方法a)。

    public void test() {
            String sql = "insert into test(name,age,create_date) values (?,?,?)";
            Date now = new Date(System.currentTimeMillis());
            //返回的是更新的行数
            int count = jdbcTemplate.update(sql, "小明", 14, now);
        }
    public void test() {
            String sql = "insert into test(name,age,create_date) values (?,?,?)";
            Date now = new Date(System.currentTimeMillis());
            //返回的是更新的行数
            int count = jdbcTemplate.update(sql, new Object[]{"小明",14,now});
        }

    这两种实际上调用的都是该方法,由此可见Object...args实际上就是可变的数组,而数组长度是固定的,必须先定义一个数组,而Object...args在传递时参数可以任意,所以也可以传递一个固定的Object数组。

        (d)int update(PreparedStatementCreator psc)

    使用该方法可以自己使用原始jdbc方式给预编译sql注入参数,来进行增加、删除、更新操作:

    public void test(final Customer customer) {//参数也是局部变量,也必须用final修饰,内部类中才能访问(全局变量不用)
            //方法局部必须是final的,匿名内部类中才能引用
            final String sql = "insert into test(name,age,create_date) values (?,?,?)";
            Date now = new Date(System.currentTimeMillis());
            //返回的是更新的行数
            int count = jdbcTemplate.update(new PreparedStatementCreator() {
                
                @Override
                public PreparedStatement createPreparedStatement(Connection conn)
                        throws SQLException {
                    PreparedStatement ps = conn.prepareStatement(sql);
                    ps.setString(1, customer.getName());
                    ps.setInt(2, customer.getAge());
                    ps.setDate(3, customer.getCreateDate());
                    
                    return ps;
                }
            });
            
        }

    如果需要返回插入的主键,只能用此方法,增加KeyHolder参数:

    public void test(final Customer customer) {//参数也是局部变量,也必须用final修饰,内部类中才能访问(全局变量不用)
            KeyHolder keyHolder = new GeneratedKeyHolder(); 
            //方法局部必须是final的,匿名内部类中才能引用
            final String sql = "insert into test(name,age,create_date) values (?,?,?)";
            Date now = new Date(System.currentTimeMillis());
            //返回的是更新的行数
            int count = jdbcTemplate.update(new PreparedStatementCreator() {
                
                @Override
                public PreparedStatement createPreparedStatement(Connection conn)
                        throws SQLException {
                    PreparedStatement ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); //有的数据库版本不一样,需要添加第二个参数,不然会报错;
              ps.setString(
    1, customer.getName());
              ps.setInt(
    2, customer.getAge());
              ps.setDate(
    3, customer.getCreateDate());
              return ps;
            }
        },keyHolder);
        
        int i = keyHolder.getKey().intValue();//这就是刚插入的数据的主键 }

    3)批量增加、删除、更新数据(多条sql语句)

      (a)批量执行多条sql(固定的sql,不需要注入参数,但是sql格式不固定

          int[] batchUpdate(final String[] sql)

    参数是一个String数组,存放多条sql语句;返回值是int数组,即每条sql更新影响的行数。

      (b)批量执行多条sql(预处理sql,需要注入参数)

        int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss)

    参数sql:一条预处理sql(如果是批量处理预处理sql,那么sql的格式就是固定的,只填充参数而已);第二个参数就是回调类,前面有统一介绍回调类。

    举两个例子,一个更新,一个插入:

    批量插入:
    public void test(final List<Customer> customer) {//参数也是局部变量,也必须用final修饰,内部类中才能访问(全局变量不用)
            
            String sql = "insert into test(name,age,create_date) values (?,?,?)";
            //返回的是更新的行数
            int[] count = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
                
                @Override
                public void setValues(PreparedStatement ps, int i)
                        throws SQLException {
                    //注入参数值
                    ps.setString(1, customer.get(i).getName());
                    ps.setInt(2, customer.get(i).getAge());
                    ps.setDate(3, customer.get(i).getCreateDate());
                }
                
                @Override
                public int getBatchSize() {
                    //批量执行的数量
                    return customer.size();
                }
            });
            
        }
    批量更新:
    public void test(final List<Customer> customer) {//参数也是局部变量,也必须用final修饰,内部类中才能访问(全局变量不用)
            String sql = "update test set name = ?,age = ? where id = ?";
            //返回的是更新的行数
            int[] count = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
                
                @Override
                public void setValues(PreparedStatement ps, int i)
                        throws SQLException {
                    //注入参数值
                    ps.setString(1, customer.get(i).getName());
                    ps.setInt(2, customer.get(i).getAge());
                    ps.setInt(3, customer.get(i).getId());
                }
                
                @Override
                public int getBatchSize() {
                    //批量执行的数量
                    return customer.size();
                }
            });
            
        }

      (c)批量处理多条预处理sql语句还有下面几种简单方法(参数和前面类似,这里就不详解):

             int[] batchUpdate(String sql, List<Object[]> batchArgs);

             int[] batchUpdate(String sql, List<Object[]> batchArgs, int[] argTypes);

  • 相关阅读:
    Chapter6 Commodity Forwards
    Chapter5 Prepaid Forwards
    个人作业5——软工个人总结
    软工网络15个人作业3
    软工网络15——结对编程
    软工网络15个人阅读作业2
    软工网络15个人阅读作业1 201521123080曾飞远
    Java课程设计 猜数游戏个人博客
    201521123080《Java程序设计》第14周学习总结
    201521123080《Java程序设计》第13周学习总结
  • 原文地址:https://www.cnblogs.com/cainiao-Shun666/p/7850948.html
Copyright © 2020-2023  润新知