zoukankan      html  css  js  c++  java
  • spring3: 对JDBC的支持 之 Spring提供的其它帮助 SimpleJdbcInsert/SimpleJdbcCall/SqlUpdate/JdbcTemplate 生成主键/批量处理

    7.4  Spring提供的其它帮助

    7.4.1  SimpleJdbc方式

           Spring JDBC抽象框架提供SimpleJdbcInsert和SimpleJdbcCall类,这两个类通过利用JDBC驱动提供的数据库元数据来简化JDBC操作。

    1、SimpleJdbcInsert: 用于插入数据,根据数据库元数据进行插入数据,本类用于简化插入操作,提供三种类型方法:execute方法用于普通插入、executeAndReturnKey及executeAndReturnKeyHolder方法用于插入时获取主键值、executeBatch方法用于批处理。

    @Test  
    public void testSimpleJdbcInsert() {  
        SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate);  
        insert.withTableName("test");  
        Map<String, Object> args = new HashMap<String, Object>();  
        args.put("name", "name5");  
        insert.compile();  
        //1.普通插入  
        insert.execute(args);  
        Assert.assertEquals(1, jdbcTemplate.queryForInt("select count(*) from test"));  
        //2.插入时获取主键值  
        insert = new SimpleJdbcInsert(jdbcTemplate);  
        insert.withTableName("test");  
        insert.setGeneratedKeyName("id");  
        Number id = insert.executeAndReturnKey(args);  
        Assert.assertEquals(1, id);  
        //3.批处理  
        insert = new SimpleJdbcInsert(jdbcTemplate);  
        insert.withTableName("test");  
        insert.setGeneratedKeyName("id");  
        int[] updateCount = insert.executeBatch(new Map[] {args, args, args});  
        Assert.assertEquals(1, updateCount[0]);  
        Assert.assertEquals(5, jdbcTemplate.queryForInt("select count(*) from test"));  
    }  
    

      

    • new SimpleJdbcInsert(jdbcTemplate)  首次通过DataSource对象或JdbcTemplate对象初始化SimpleJdbcInsert;
    • insert.withTableName("test")  用于设置数据库表名;
    • args  用于指定插入时列名及值,如本例中只有name列名,即编译后的sql类似于“insert into test(name) values(?)”;
    • insert.compile()  可选的编译步骤,在调用执行方法时自动编译,编译后不能再对insert对象修改;
    • 执行: execute方法用于执行普通插入;executeAndReturnKey用于执行并获取自动生成主键(注意是Number类型),必须首先通过setGeneratedKeyName设置主键然后才能获取,如果想获取复合主键请使用setGeneratedKeyNames描述主键然后通过executeReturningKeyHolder获取复合主键KeyHolder对象;executeBatch用于批处理;

    2、SimpleJdbcCall: 用于调用存储过程及自定义函数,本类用于简化存储过程及自定义函数调用。

    @Test  
    public void testSimpleJdbcCall1() {  
        //此处用mysql,因为hsqldb调用自定义函数和存储过程一样  
        SimpleJdbcCall call = new SimpleJdbcCall(getMysqlDataSource());  
        call.withFunctionName("FUNCTION_TEST");  
        call.declareParameters(new SqlOutParameter("result", Types.INTEGER));  
        call.declareParameters(new SqlParameter("str", Types.VARCHAR));  
        Map<String, Object> outVlaues = call.execute("test");  
        Assert.assertEquals(4, outVlaues.get("result"));  
    }  
    

      

    • new SimpleJdbcCall(getMysqlDataSource()) :通过DataSource对象或JdbcTemplate对象初始化SimpleJdbcCall;
    • withFunctionName("FUNCTION_TEST")  定义自定义函数名;自定义函数sql语句将被编译为类似于{?= call …}形式;
    • declareParameters  描述参数类型,使用方式与StoredProcedure对象一样;
    • 执行: 调用execute方法执行自定义函数;
    @Test  
    public void testSimpleJdbcCall2() {  
        //调用hsqldb自定义函数得使用如下方式  
        SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate);  
        call.withProcedureName("FUNCTION_TEST");  
    call.declareParameters(new SqlReturnResultSet("result",  
    new ResultSetExtractor<Integer>() {  
            @Override  
            public Integer extractData(ResultSet rs)  
    throws SQLException, DataAccessException {  
              while(rs.next()) {  
                return rs.getInt(1);  
              }  
              return 0;  
        }}));  
        call.declareParameters(new SqlParameter("str", Types.VARCHAR));  
        Map<String, Object> outVlaues = call.execute("test");  
        Assert.assertEquals(4, outVlaues.get("result"));  
    }  
    

      调用hsqldb数据库自定义函数与调用mysql自定义函数完全不同,详见StoredProcedure中的解释。

    @Test  
    public void testSimpleJdbcCall3() {  
      SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate);  
      call.withProcedureName("PROCEDURE_TEST");  
      call.declareParameters(new SqlInOutParameter("inOutName", Types.VARCHAR));  
      call.declareParameters(new SqlOutParameter("outId", Types.INTEGER));  
      SqlParameterSource params =  
      new MapSqlParameterSource().addValue("inOutName", "test");  
      Map<String, Object> outVlaues = call.execute(params);  
      Assert.assertEquals("Hello,test", outVlaues.get("inOutName"));  
      Assert.assertEquals(0, outVlaues.get("outId"));  
    }  
    

      

    与自定义函数调用不同的是使用withProcedureName来指定存储过程名字;其他参数描述等完全一样。

     

    7.4.2  控制数据库连接

           Spring JDBC通过DataSource控制数据库连接,即通过DataSource实现获取数据库连接。

           Spring JDBC提供了一下DataSource实现:

    • DriverManagerDataSource :简单封装了DriverManager获取数据库连接;通过DriverManager的getConnection方法获取数据库连接;
    • SingleConnectionDataSource :内部封装了一个连接,该连接使用后不会关闭,且不能在多线程环境中使用,一般用于测试;
    • LazyConnectionDataSourceProxy :包装一个DataSource,用于延迟获取数据库连接,只有在真正创建Statement等时才获取连接,因此再说实际项目中最后使用该代理包装原始DataSource从而使得只有在真正需要连接时才去获取。

    第三方提供的DataSource实现主要有C3P0、Proxool、DBCP等,这些实现都具有数据库连接池能力。

    DataSourceUtils: Spring JDBC抽象框架内部都是通过它的getConnection(DataSource dataSource)方法获取数据库连接,releaseConnection(Connection con, DataSource dataSource) 用于释放数据库连接,DataSourceUtils用于支持Spring管理事务,只有使用DataSourceUtils获取的连接才具有Spring管理事务。

     

    7.4.3  获取自动生成的主键

           有许多数据库提供自动生成主键的能力,因此我们可能需要获取这些自动生成的主键,JDBC 3.0标准支持获取自动生成的主键,且必须数据库支持自动生成键获取。

    1 )JdbcTemplate 获取自动生成主键方式:

    @Test  
    public void testFetchKey1() throws SQLException {  
        final String insertSql = "insert into test(name) values('name5')";  
        KeyHolder generatedKeyHolder = new GeneratedKeyHolder();  
        jdbcTemplate.update(new PreparedStatementCreator() {  
            @Override  
           public PreparedStatement createPreparedStatement(Connection conn)  
                throws SQLException {  
                return conn.prepareStatement(insertSql, new String[]{"ID"});  
          }}, generatedKeyHolder);  
        Assert.assertEquals(0, generatedKeyHolder.getKey());  
    }  
    

      

    使用JdbcTemplate的update(final PreparedStatementCreator psc, final KeyHolder generatedKeyHolder)方法执行需要返回自动生成主键的插入语句,其中psc用于创建PreparedStatement并指定自动生成键,如“prepareStatement(insertSql, new String[]{"ID"})”;generatedKeyHolder是KeyHolder类型,用于获取自动生成的主键或复合主键;如使用getKey方法获取自动生成的主键。

    2 )SqlUpdate 获取自动生成主键方式:

    @Test  
    public void testFetchKey2() {  
        final String insertSql = "insert into test(name) values('name5')";  
        KeyHolder generatedKeyHolder = new GeneratedKeyHolder();  
        SqlUpdate update = new SqlUpdate();  
        update.setJdbcTemplate(jdbcTemplate);  
        update.setReturnGeneratedKeys(true);  
        //update.setGeneratedKeysColumnNames(new String[]{"ID"});  
        update.setSql(insertSql);  
        update.update(null, generatedKeyHolder);  
        Assert.assertEquals(0, generatedKeyHolder.getKey());  
    }  
    

      

    SqlUpdate获取自动生成主键方式和JdbcTemplate完全一样,可以使用setReturnGeneratedKeys(true)表示要获取自动生成键;也可以使用setGeneratedKeysColumnNames指定自动生成键列名。

    3 )SimpleJdbcInsert  前边示例已介绍,此处就不演示了。

     

    7.4.4  JDBC批量操作

           JDBC批处理用于减少与数据库交互的次数来提升性能,Spring JDBC抽象框架通过封装批处理操作来简化批处理操作

    1 )JdbcTemplate 批处理: 支持普通的批处理及占位符批处理;

    @Test  
    public void testBatchUpdate1() {  
        String insertSql = "insert into test(name) values('name5')";  
        String[] batchSql = new String[] {insertSql, insertSql};  
        jdbcTemplate.batchUpdate(batchSql);  
        Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));  
    }  
    

       直接调用batchUpdate方法执行需要批处理的语句即可。

    @Test  
    public void testBatchUpdate2() {  
        String insertSql = "insert into test(name) values(?)";  
        final String[] batchValues = new String[] {"name5", "name6"};  
        jdbcTemplate.batchUpdate(insertSql, new BatchPreparedStatementSetter() {  
            @Override  
            public void setValues(PreparedStatement ps, int i) throws SQLException {  
                ps.setString(1, batchValues[i]);  
            }  
            @Override  
            public int getBatchSize() {  
                return batchValues.length;  
            }  
        });  
        Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));  
    }  
    

      

      JdbcTemplate还可以通过batchUpdate(String sql, final BatchPreparedStatementSetter pss)方法进行批处理,该方式使用预编译语句,然后通过BatchPreparedStatementSetter实现进行设值(setValues)及指定批处理大小(getBatchSize)。

    2 )NamedParameterJdbcTemplate 批处理: 支持命名参数批处理;

    @Test  
    public void testBatchUpdate3() {  
        NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);  
        String insertSql = "insert into test(name) values(:myName)";  
        UserModel model = new UserModel();  
        model.setMyName("name5");  
        SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(new Object[] {model, model});  
        namedParameterJdbcTemplate.batchUpdate(insertSql, params);  
        Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));  
    }  
    

      

    通过batchUpdate(String sql, SqlParameterSource[] batchArgs)方法进行命名参数批处理,batchArgs指定批处理数据集。SqlParameterSourceUtils.createBatch用于根据JavaBean对象或者Map创建相应的BeanPropertySqlParameterSource或MapSqlParameterSource。

    3) SimpleJdbcTemplate 批处理: 已更简单的方式进行批处理;

    @Test  
    public void testBatchUpdate4() {  
        SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(jdbcTemplate);  
        String insertSql = "insert into test(name) values(?)";  
        List<Object[]> params = new ArrayList<Object[]>();  
        params.add(new Object[]{"name5"});  
        params.add(new Object[]{"name5"});  
        simpleJdbcTemplate.batchUpdate(insertSql, params);  
        Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));  
    }  
    

      

      本示例使用batchUpdate(String sql, List<Object[]> batchArgs)方法完成占位符批处理,当然也支持命名参数批处理等。

    4 )SimpleJdbcInsert 批处理:

    @Test  
    public void testBatchUpdate5() {  
        SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate);  
        insert.withTableName("test");  
        Map<String, Object> valueMap = new HashMap<String, Object>();  
        valueMap.put("name", "name5");  
        insert.executeBatch(new Map[] {valueMap, valueMap});  
       Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));  
    }  
    

       如代码所示,使用executeBatch(Map<String, Object>[] batch)方法执行批处理。       

  • 相关阅读:
    FZU 2098 刻苦的小芳(卡特兰数,动态规划)
    卡特兰数总结
    FZU 1064 教授的测试(卡特兰数,递归)
    HDU 4745 Two Rabbits(区间DP,最长非连续回文子串)
    Java 第十一届 蓝桥杯 省模拟赛 正整数的摆动序列
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 反倍数
    Java 第十一届 蓝桥杯 省模拟赛 凯撒密码加密
    Java 第十一届 蓝桥杯 省模拟赛 凯撒密码加密
  • 原文地址:https://www.cnblogs.com/achengmu/p/8696099.html
Copyright © 2011-2022 走看看