zoukankan      html  css  js  c++  java
  • Spring JdbcTemplate方法详解

    JdbcTemplate主要提供以下五类方法:
    • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
    • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
    • query方法及queryForXXX方法:用于执行查询相关语句;
    • call方法:用于执行存储过程、函数相关语句。

    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)来处理结果集,用户必须处理整个结果集;

    接下来让我们看下具体示例吧,在示例中不可能介绍到JdbcTemplate全部方法及回调类的使用方法,我们只介绍代表性的,其余的使用都是类似的;

    1)预编译语句及存储过程创建回调、自定义功能回调使用:

    java代码:
    Java代码  收藏代码
    1. @Test  
    2. public void testPpreparedStatement1() {  
    3.   int count = jdbcTemplate.execute(new PreparedStatementCreator() {  
    4.      @Override  
    5.      public PreparedStatement createPreparedStatement(Connection conn)  
    6.          throws SQLException {  
    7.          return conn.prepareStatement("select count(*) from test");  
    8.      }}, new PreparedStatementCallback<Integer>() {  
    9.      @Override  
    10.      public Integer doInPreparedStatement(PreparedStatement pstmt)  
    11.          throws SQLException, DataAccessException {  
    12.          pstmt.execute();  
    13.          ResultSet rs = pstmt.getResultSet();  
    14.          rs.next();  
    15.          return rs.getInt(1);  
    16.       }});      
    17.    Assert.assertEquals(0, count);  
    18. }  
    19.    

    首先使用PreparedStatementCreator创建一个预编译语句,其次由JdbcTemplate通过PreparedStatementCallback回调传回,由用户决定如何执行该PreparedStatement。此处我们使用的是execute方法。

    2)预编译语句设值回调使用:

    java代码:
    Java代码  收藏代码
    1.       
    2. @Test  
    3. public void testPreparedStatement2() {  
    4.   String insertSql = "insert into test(name) values (?)";  
    5.   int count = jdbcTemplate.update(insertSql, new PreparedStatementSetter() {  
    6.       @Override  
    7.       public void setValues(PreparedStatement pstmt) throws SQLException {  
    8.           pstmt.setObject(1"name4");  
    9.   }});  
    10.   Assert.assertEquals(1, count);      
    11.   String deleteSql = "delete from test where name=?";  
    12.   count = jdbcTemplate.update(deleteSql, new Object[] {"name4"});  
    13.   Assert.assertEquals(1, count);  
    14. }  

          通过JdbcTemplate的int update(String sql, PreparedStatementSetter pss)执行预编译sql,其中sql参数为“insert into test(name) values (?) ”,该sql有一个占位符需要在执行前设值,PreparedStatementSetter实现就是为了设值,使用setValues(PreparedStatement pstmt)回调方法设值相应的占位符位置的值。JdbcTemplate也提供一种更简单的方式“update(String sql, Object... args)”来实现设值,所以只要当使用该种方式不满足需求时才应使用PreparedStatementSetter。

    3)结果集处理回调:

    java代码:
    Java代码  收藏代码
    1. @Test  
    2. public void testResultSet1() {  
    3.   jdbcTemplate.update("insert into test(name) values('name5')");  
    4.   String listSql = "select * from test";  
    5.   List result = jdbcTemplate.query(listSql, new RowMapper<Map>() {  
    6.       @Override  
    7.       public Map mapRow(ResultSet rs, int rowNum) throws SQLException {  
    8.           Map row = new HashMap();  
    9.           row.put(rs.getInt("id"), rs.getString("name"));  
    10.           return row;  
    11.   }});  
    12.   Assert.assertEquals(1, result.size());  
    13.   jdbcTemplate.update("delete from test where name='name5'");       
    14. }  

    RowMapper接口提供mapRow(ResultSet rs, int rowNum)方法将结果集的每一行转换为一个Map,当然可以转换为其他类,如表的对象画形式。

    java代码:
    Java代码  收藏代码
    1. @Test  
    2. public void testResultSet2() {  
    3.   jdbcTemplate.update("insert into test(name) values('name5')");  
    4.   String listSql = "select * from test";  
    5.   final List result = new ArrayList();  
    6.   jdbcTemplate.query(listSql, new RowCallbackHandler() {  
    7.       @Override  
    8.       public void processRow(ResultSet rs) throws SQLException {  
    9.           Map row = new HashMap();  
    10.           row.put(rs.getInt("id"), rs.getString("name"));  
    11.           result.add(row);  
    12.   }});  
    13.   Assert.assertEquals(1, result.size());  
    14.   jdbcTemplate.update("delete from test where name='name5'");  
    15. }  

    RowCallbackHandler接口也提供方法processRow(ResultSet rs),能将结果集的行转换为需要的形式。

    java代码:
    Java代码  收藏代码
    1. @Test  
    2. public void testResultSet3() {  
    3.   jdbcTemplate.update("insert into test(name) values('name5')");  
    4.   String listSql = "select * from test";  
    5.   List result = jdbcTemplate.query(listSql, new ResultSetExtractor<List>() {  
    6.       @Override  
    7.       public List extractData(ResultSet rs)  
    8.      throws SQLException, DataAccessException {  
    9.           List result = new ArrayList();  
    10.           while(rs.next()) {  
    11.               Map row = new HashMap();  
    12.               row.put(rs.getInt("id"), rs.getString("name"));  
    13.               result.add(row);  
    14.            }  
    15.            return result;  
    16.   }});  
    17.   Assert.assertEquals(0, result.size());  
    18.   jdbcTemplate.update("delete from test where name='name5'");  
    19. }  

    ResultSetExtractor使用回调方法extractData(ResultSet rs)提供给用户整个结果集,让用户决定如何处理该结果集。

    当然JdbcTemplate提供更简单的queryForXXX方法,来简化开发:

    java代码:
    Java代码  收藏代码
    1. //1.查询一行数据并返回int型结果  
    2. jdbcTemplate.queryForInt("select count(*) from test");  
    3. //2. 查询一行数据并将该行数据转换为Map返回  
    4. jdbcTemplate.queryForMap("select * from test where name='name5'");  
    5. //3.查询一行任何类型的数据,最后一个参数指定返回结果类型  
    6. jdbcTemplate.queryForObject("select count(*) from test", Integer.class);  
    7. //4.查询一批数据,默认将每行数据转换为Map       
    8. jdbcTemplate.queryForList("select * from test");  
    9. //5.只查询一列数据列表,列类型是String类型,列名字是name  
    10. jdbcTemplate.queryForList("  
    11. select name from test where name=?", new Object[]{"name5"}, String.class);  
    12. //6.查询一批数据,返回为SqlRowSet,类似于ResultSet,但不再绑定到连接上  
    13. SqlRowSet rs = jdbcTemplate.queryForRowSet("select * from test");  

    3) 存储过程及函数回调:

    首先修改JdbcTemplateTest的setUp方法,修改后如下所示:

    java代码:
    Java代码  收藏代码
    1.       
    2. @Before  
    3. public void setUp() {  
    4.     String createTableSql = "create memory table test" +  
    5.     "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " +  
    6.     "name varchar(100))";  
    7.     jdbcTemplate.update(createTableSql);  
    8.          
    9.     String createHsqldbFunctionSql =  
    10.       "CREATE FUNCTION FUNCTION_TEST(str CHAR(100)) " +  
    11.       "returns INT begin atomic return length(str);end";  
    12.     jdbcTemplate.update(createHsqldbFunctionSql);  
    13.     String createHsqldbProcedureSql =  
    14.       "CREATE PROCEDURE PROCEDURE_TEST" +  
    15.       "(INOUT inOutName VARCHAR(100), OUT outId INT) " +  
    16.       "MODIFIES SQL DATA " +  
    17.       "BEGIN ATOMIC " +  
    18.       "  insert into test(name) values (inOutName); " +  
    19.       "  SET outId = IDENTITY(); " +  
    20.       "  SET inOutName = 'Hello,' + inOutName; " +  
    21.     "END";  
    22.     jdbcTemplate.execute(createHsqldbProcedureSql);  
    23. }  

           其中CREATE FUNCTION FUNCTION_TEST用于创建自定义函数,CREATE PROCEDURE PROCEDURE_TEST用于创建存储过程,注意这些创建语句是数据库相关的,本示例中的语句只适用于HSQLDB数据库。

           其次修改JdbcTemplateTest的tearDown方法,修改后如下所示:

    java代码:
    Java代码  收藏代码
    1. @After  
    2. public void tearDown() {  
    3.     jdbcTemplate.execute("DROP FUNCTION FUNCTION_TEST");  
    4.     jdbcTemplate.execute("DROP PROCEDURE PROCEDURE_TEST");  
    5.     String dropTableSql = "drop table test";  
    6.     jdbcTemplate.execute(dropTableSql);  
    7. }  

           其中drop语句用于删除创建的存储过程、自定义函数及数据库表。

           接下来看一下hsqldb如何调用自定义函数:

    java代码:
    Java代码  收藏代码
    1. @Test  
    2. public void testCallableStatementCreator1() {  
    3.     final String callFunctionSql = "{call FUNCTION_TEST(?)}";  
    4.     List<SqlParameter> params = new ArrayList<SqlParameter>();  
    5.     params.add(new SqlParameter(Types.VARCHAR));  
    6.     params.add(new SqlReturnResultSet("result",  
    7.        new ResultSetExtractor<Integer>() {  
    8.            @Override  
    9.            public Integer extractData(ResultSet rs) throws SQLException,  
    10.                DataAccessException {  
    11.                while(rs.next()) {  
    12.                    return rs.getInt(1);  
    13.                }  
    14.               return 0;  
    15.        }));  
    16.     Map<String, Object> outValues = jdbcTemplate.call(  
    17.        new CallableStatementCreator() {  
    18.             @Override  
    19.             public CallableStatement createCallableStatement(Connection conn) throws SQLException {  
    20.               CallableStatement cstmt = conn.prepareCall(callFunctionSql);  
    21.               cstmt.setString(1"test");  
    22.               return cstmt;  
    23.     }}, params);  
    24.     Assert.assertEquals(4, outValues.get("result"));  
    25. }  
    26.    
    • {call FUNCTION_TEST(?)}:定义自定义函数的sql语句,注意hsqldb {?= call …}和{call …}含义是一样的,而比如mysql中两种含义是不一样的;
    • params:用于描述自定义函数占位符参数或命名参数类型;SqlParameter用于描述IN类型参数、SqlOutParameter用于描述OUT类型参数、SqlInOutParameter用于描述INOUT类型参数、SqlReturnResultSet用于描述调用存储过程或自定义函数返回的ResultSet类型数据,其中SqlReturnResultSet需要提供结果集处理回调用于将结果集转换为相应的形式,hsqldb自定义函数返回值是ResultSet类型。
    • CallableStatementCreator:提供Connection对象用于创建CallableStatement对象
    • outValues:调用call方法将返回类型为Map<String, Object>对象;
    • outValues.get("result"):获取结果,即通过SqlReturnResultSet对象转换过的数据;其中SqlOutParameter、SqlInOutParameter、SqlReturnResultSet指定的name用于从call执行后返回的Map中获取相应的结果,即name是Map的键。

    注:因为hsqldb {?= call …}和{call …}含义是一样的,因此调用自定义函数将返回一个包含结果的ResultSet。

    最后让我们示例下MySQL如何调用自定义函数:

    java代码:
    Java代码  收藏代码
    1. @Test  
    2. public void testCallableStatementCreator2() {  
    3.     JdbcTemplate mysqlJdbcTemplate = new JdbcTemplate(getMysqlDataSource);  
    4.     //2.创建自定义函数  
    5. String createFunctionSql =  
    6.     "CREATE FUNCTION FUNCTION_TEST(str VARCHAR(100)) " +  
    7.      "returns INT return LENGTH(str)";  
    8. String dropFunctionSql = "DROP FUNCTION IF EXISTS FUNCTION_TEST";  
    9. mysqlJdbcTemplate.update(dropFunctionSql);         
    10. mysqlJdbcTemplate.update(createFunctionSql);  
    11. //3.准备sql,mysql支持{?= call …}  
    12. final String callFunctionSql = "{?= call FUNCTION_TEST(?)}";  
    13. //4.定义参数  
    14. List<SqlParameter> params = new ArrayList<SqlParameter>();  
    15. params.add(new SqlOutParameter("result", Types.INTEGER));  
    16. params.add(new SqlParameter("str", Types.VARCHAR));  
    17. Map<String, Object> outValues = mysqlJdbcTemplate.call(  
    18. new CallableStatementCreator() {  
    19.     @Override  
    20.     public CallableStatement createCallableStatement(Connection conn) throws SQLException {  
    21.       CallableStatement cstmt = conn.prepareCall(callFunctionSql);  
    22.       cstmt.registerOutParameter(1, Types.INTEGER);  
    23.       cstmt.setString(2"test");  
    24.         return cstmt;  
    25.     }}, params);  
    26.    Assert.assertEquals(4, outValues.get("result"));  
    27. }  
    28. public DataSource getMysqlDataSource() {  
    29.     String url = "jdbc:mysql://localhost:3306/test";  
    30.     DriverManagerDataSource dataSource =  
    31.         new DriverManagerDataSource(url, "root""");     dataSource.setDriverClassName("com.mysql.jdbc.Driver");  
    32.     return dataSource;  
    33. }  
    34.    
    • getMysqlDataSource:首先启动mysql(本书使用5.4.3版本),其次登录mysql创建test数据库(“create database test;”),在进行测试前,请先下载并添加mysql-connector-java-5.1.10.jar到classpath;
    • {?= call FUNCTION_TEST(?)}:可以使用{?= call …}形式调用自定义函数;
    • params:无需使用SqlReturnResultSet提取结果集数据,而是使用SqlOutParameter来描述自定义函数返回值;
    • CallableStatementCreator:同上个例子含义一样;
    • cstmt.registerOutParameter(1, Types.INTEGER):将OUT类型参数注册为JDBC类型Types.INTEGER,此处即返回值类型为Types.INTEGER。
    • outValues.get("result"):获取结果,直接返回Integer类型,比hsqldb简单多了吧。

    最后看一下如何如何调用存储过程:

    java代码:
    Java代码  收藏代码
    1. @Test  
    2. public void testCallableStatementCreator3() {  
    3.     final String callProcedureSql = "{call PROCEDURE_TEST(?, ?)}";  
    4.     List<SqlParameter> params = new ArrayList<SqlParameter>();  
    5.     params.add(new SqlInOutParameter("inOutName", Types.VARCHAR));  
    6.     params.add(new SqlOutParameter("outId", Types.INTEGER));  
    7.     Map<String, Object> outValues = jdbcTemplate.call(  
    8.       new CallableStatementCreator() {  
    9.         @Override  
    10.         public CallableStatement createCallableStatement(Connection conn) throws SQLException {  
    11.           CallableStatement cstmt = conn.prepareCall(callProcedureSql);  
    12.           cstmt.registerOutParameter(1, Types.VARCHAR);  
    13.           cstmt.registerOutParameter(2, Types.INTEGER);  
    14.           cstmt.setString(1"test");  
    15.           return cstmt;  
    16.     }}, params);  
    17.     Assert.assertEquals("Hello,test", outValues.get("inOutName"));  
    18.     Assert.assertEquals(0, outValues.get("outId"));  
    19. }  
    20.    
    • {call PROCEDURE_TEST(?, ?)}:定义存储过程sql;
    • params:定义存储过程参数;SqlInOutParameter描述INOUT类型参数、SqlOutParameter描述OUT类型参数;
    • CallableStatementCreator:用于创建CallableStatement,并设值及注册OUT参数类型;
    • outValues:通过SqlInOutParameter及SqlOutParameter参数定义的name来获取存储过程结果。
           JdbcTemplate类还提供了很多便利方法,在此就不一一介绍了,但这些方法是由规律可循的,第一种就是提供回调接口让用户决定做什么,第二种可以认为是便利方法(如queryForXXX),用于那些比较简单的操作。
  • 相关阅读:
    How to install VXDIAG Honda, Toyota and JLR SDD software
    16% off MPPS V16 ECU tuning tool for EDC15 EDC16 EDC17
    Cummins INSITE locked and ask for verification code
    How to use BMW Multi Tool 7.3 to replace lost key for BMW X1
    Bleed Brake Master Cylinder with Intelligent Tester IT2
    Porsche Piwis Tester II “No VCI has been detected”,how to do?
    Creader VIII VS. Creader VII+
    How to solve GM MDI cannot complete the installation
    汽车OBD2诊断程序开发 (原文转载,思路很清晰!)
    汽车节温器单片机开发思路
  • 原文地址:https://www.cnblogs.com/archermeng/p/7537400.html
Copyright © 2011-2022 走看看