template标签是什么意思(vue的template用法)

jdbcTemplate.queryForObject方法入参不支持以Map的形式传递参数,需要按照sql语句中参数的顺序组织入参的List。jdbcTemplate.queryForObject方法直接不支持的in查询。只支持Integer.class String.class 这种单数据类型的入参。

  • 例如:
List<Long> idList = ...;String name = ...;StringBuilder idListSb = new StringBuilder();for(Long id : idList){  idListSb.append(id + \",\");}String sql = \"select count(*) from user where id in (?) and name = ?\";List<Object> objects = new ArrayList<>();objects.add(idListSb.toString().RTrim(\',\'));object.add (name);jdbcTemplate.queryForObject(sb.toString(),objects,Long.class);

而NamedParameterJdbcTemplate时,其本来就支持in查询和Map类型的入参。

List<Long> idList = ...;String name = ...;String sql = \"select * from user where id in (:ids) and name = :name\";Map<String, Object> param  = new HashMap<>();param.put(\"ids\", idList);param.put(\"name\", name);namedParameterJdbcTemplate.queryForObject(sb.toString(),param,Long.class);

一、JdbcTemplate

Spring对数据库的操作在jdbc上面做了深层次的封装,提供了一个 Jdbc Template 类,我们可以直接使用。只需要把DataSource注册到JdbcTemplate之中,其全限定命名为org.springframework.jdbc.core.JdbcTemplate。要使用JdbcTemlate一般还需要事务和异常的控制。

JdbcTemplate的几类方法

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

JdbcTemplate的常用方法

//update操作单个增删改int update(String sql,Object[] args)int update(String sql,Objcet... args)//batchUpdate批量增删改int[] batchUpdate(String[] sql)int[] batchUpdate(String sql,List<Object[]>)//单个简单查询T queryForObjcet(String sql,Class<T> type)T queryForObjcet(String sql,Object[] args,Class<T> type)T queryForObjcet(String sql,Class<T> type,Object... arg)//获取多个List<T> queryForList(String sql,Class<T> type)List<T> queryForList(String sql,Object[] args,Class<T> type)List<T> queryForList(String sql,Class<T> type,Object... arg)

查询复杂对象(封装为Map)

//获取单个Map queryForMap(String sql)Map queryForMap(String sql,Objcet[] args)Map queryForMap(String sql,Object... arg)//获取多个List<Map<String,Object>> queryForList(String sql)List<Map<String,Object>> queryForList(String sql,Obgject[] args)List<Map<String,Object>> queryForList(String sql,Obgject... arg)

查询复杂对象(封装为实体对象)

Spring JdbcTemplate是通过实现org.springframework.jdbc.core.RowMapper这个接口来完成对entity对象映射。

//获取单个T queryForObject(String sql,RowMapper<T> mapper)T queryForObject(String sql,object[] args,RowMapper<T> mapper)T queryForObject(String sql,RowMapper<T> mapper,Object... arg)//获取多个List<T> query(String sql,RowMapper<T> mapper)List<T> query(String sql,Object[] args,RowMapper<T> mapper)List<T> query(String sql,RowMapper<T> mapper,Object... arg)

Spring JDBC中目前有两个主要的RowMapper实现,使用它们应该能解决大部分的场景了:SingleColumnRowMapper和BeanPropertyRowMapper。SingleColumnRowMapper:返回单列数据BeanPropertyRowMapper:当查询数据库返回的是多列数据,且需要将这些多列数据映射到某个具体的实体类上。

//示例:String sql = \"select name from test_student where id = ?\";jdbcTemplate.queryForObject(sql, new Object[]{id}, new SingleColumnRowMapper<>(String.class));String sql = \"select name, gender from test_student where name = ?\";jdbcTemplate.queryForObject(sql, new Object[]{name},new BeanPropertyRowMapper<>(Student.class));
  • 定义自己的RowMapper

如果你SQL查询出来的数据列名就是和实体类的属性名不一样,或者想按照自己的规则来装配实体类,那么就可以定义并使用自己的Row Mapper。

//自定义public class StudentRowMapper implements RowMapper<Student> {    @Override    public Student mapRow(ResultSet rs, int i) throws SQLException {        Student student = new Student();        student.setName(rs.getString(\"name\"));        student.setGender(rs.getString(\"gender\"));        student.setEmail(rs.getString(\"email\"));        return student;    }}//使用String sql = \"select name, gender, email from test_student where name = ?\";jdbcTemplate.queryForObject(sql, new Object[]{name}, new StudentRowMapper());

批量修改

public int[] batchInsert(List<Map<String, Object>> dataList) {    String sql = \"INSERT INTO test_info(name, create_time, age) VALUES(?, NOW(), ?)\";    List<Object[]> paramArray = new ArrayList<>();    for (Map<String, Object> dataInfo : dataList) {        Object[] obj = new Object[2];        obj[0] = dataInfo.get(\"name\");        obj[1] = dataInfo.get(\"age\");        paramArray.add(obj);    }    if (CollectionUtils.isNotEmpty(paramArray)) {        return jdbcTemplate.batchUpdate(sql, paramArray);    }    return new int[0];}

JdbcTemplate支持的回调类

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

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

import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.dao.DataAccessException;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.PreparedStatementCallback;import org.springframework.jdbc.core.PreparedStatementCreator;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) // 关联Spring与Junit@ContextConfiguration(locations = { \"classpath:applicationContext.xml\" }) // 加载配置spring配置文件public class AppTest {    @Autowired    private JdbcTemplate jdbcTemplate;    @Test    public void testPpreparedStatement1() {        int count = jdbcTemplate.execute(new PreparedStatementCreator() {            public java.sql.PreparedStatement createPreparedStatement(Connection conn) throws SQLException {                return conn.prepareStatement(\"select count(*) from user\");            }        }, new PreparedStatementCallback<Integer>() {            public Integer doInPreparedStatement(java.sql.PreparedStatement pstmt)                    throws SQLException, DataAccessException {                pstmt.execute();                ResultSet rs = pstmt.getResultSet();                rs.next();                return rs.getInt(1);            }        });        System.out.println(count);    }}

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

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

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

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

import java.sql.PreparedStatement;import java.sql.SQLException;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.PreparedStatementSetter;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class) // 关联Spring与Junit@ContextConfiguration(locations = { \"classpath:applicationContext.xml\" }) // 加载配置spring配置文件public class AppTest {    @Autowired    private JdbcTemplate jdbcTemplate;    @Test    public void testPreparedStatement2() {        String insertSql = \"insert into user(user_name) values (?)\";        int count = jdbcTemplate.update(insertSql, new PreparedStatementSetter() {            public void setValues(PreparedStatement pstmt) throws SQLException {                pstmt.setObject(1, \"mmNN\");            }        });        Assert.assertEquals(1, count);        String deleteSql = \"delete from user where user_name=?\";        count = jdbcTemplate.update(deleteSql, new Object[] { \"mmNN\" });        Assert.assertEquals(1, count);    }}

通过JdbcTemplate的int update(String sql, PreparedStatementSetter pss)执行预编译sql,其中sql参数为“insert into user(user_name) values (?) ”,该sql有一个占位符需要在执行前设值,PreparedStatementSetter实现就是为了设值,使用setValues(PreparedStatement pstmt)回调方法设值相应的占位符位置的值。JdbcTemplate也提供一种更简单的方式“update(String sql, Object… args)”来实现设值,所以只要当使用该种方式不满足需求时才应使用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)来处理结果集,用户必须处理整个结果集;

@Testpublic void testResultSet1() {    jdbcTemplate.update(\"insert into user(user_name) values(\'name7\')\");    String listSql = \"select * from user where user_name=?\";    List result = jdbcTemplate.query(listSql,new Object[]{\"name7\"}, new RowMapper<Map>() {        public Map mapRow(ResultSet rs, int rowNum) throws SQLException {            Map row = new HashMap();            row.put(rs.getInt(\"user_id\"), rs.getString(\"user_name\"));            return row;        }    });    Assert.assertEquals(1, result.size());//查询结果数量为1才向下执行    jdbcTemplate.update(\"delete from user where user_name=\'name7\'\");}

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

@Testpublic void testResultSet2() {    jdbcTemplate.update(\"insert into user(user_name) values(\'name5\')\");    String listSql = \"select * from user\";    final List result = new ArrayList();    jdbcTemplate.query(listSql, new RowCallbackHandler() {        public void processRow(ResultSet rs) throws SQLException {            Map row = new HashMap();            row.put(rs.getInt(\"user_id\"), rs.getString(\"user_name\"));            result.add(row);        }    });    Assert.assertEquals(1, result.size());    jdbcTemplate.update(\"delete from user where user_name=\'name5\'\");}

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

@Testpublic void testResultSet3() {    jdbcTemplate.update(\"insert into test(name) values(\'name5\')\");    String listSql = \"select * from test\";    List result = jdbcTemplate.query(listSql, new ResultSetExtractor<List>() {        public List extractData(ResultSet rs) throws SQLException, DataAccessException {            List result = new ArrayList();            while (rs.next()) {                Map row = new HashMap();                row.put(rs.getInt(\"id\"), rs.getString(\"name\"));                result.add(row);            }            return result;        }    });    Assert.assertEquals(0, result.size());    jdbcTemplate.update(\"delete from test where name=\'name5\'\");}

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

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

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

返回新增的自增ID

@Testpublic void test(){    String sql = \"insert into sp_user(name) values (?)\";    KeyHolder keyHolder = new GeneratedKeyHolder();    jdbcTemplate.update(new PreparedStatementCreator() {        @Override        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {            // 设置返回的主键字段名            PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);            ps.setString(1, \"harvey\");            return ps;        }    }, keyHolder);    // 获取到插入数据生成的ID    int num = keyHolder.getKey().intValue();    System.out.println(num);}

二、NamedParameterJdbcTemplate

什么是具名参数

在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制。定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定。在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择是使用具名参数(named parameter)。

具名参数:SQL 按名称(以冒号开头)而不是按位置进行指定,具名参数更易于维护,,也提升了可读性。具名参数由框架类在运行时用占位符取代,具名参数只在NamedParameterJdbcTemplate 中得到支持。

NamedParameterJdbcTemplate类拓展了JdbcTemplate类,可以使用全部jdbcTemplate方法。

NamedParameterJdbcTemplate主要提供以下三类方法:execute方法、query及queryForXXX方法、update及batchUpdate方法。

NamedParameterJdbcTemplate可以使用DataSource或JdbcTemplate 对象作为构造器参数初始化。

常用API传入参数类型介绍

NamedParameterJdbcTemplate类为命名参数设值有两种方式:java.util.Map 、RowMapper 和 SqlParameterSource。

Map<String,?> paramMap

就是一个hash表,好处是可以根据参数名传参,paramMap.put(“sqlparamName”,value)。

RowMapper rowMapper

这个接口为了实现sql查询结果和对象间的转换,可以自己实现,也可以使用系统实现,主要实现类有:

  • SingleColumnRowMapper ,sql结果为一个单列的数据,如List<String> , List<Integer>,String,Integer等
  • BeanPropertyRowMapper, sql结果匹配到对象 List< XxxVO> , XxxVO

SqlParameterSource

其作用和Map一样,就是为sql中的条件参数赋值,默认实现有 :

  • MapSqlParameterSource实现非常简单,只是封装了java.util.Map。
  • BeanPropertySqlParameterSource封装了一个JavaBean对象,通过JavaBean对象属性来决定命名参数的值。
  • EmptySqlParameterSource 一个空的SqlParameterSource ,常用来占位使用。
//BeanPropertySqlParameterSource传参方式SqlParameterSource sps = new BeanPropertySqlParameterSource(javaBean);//MapSqlParameterSource传参方式SqlParameterSource sps = new MapSqlParameterSource();//保证参数名和key相同sps.addValue(\"key\",value);

API介绍

查询

返回单行单列数据

public < T > T queryForObject(String sql, Map<String, ?> paramMap, Class<T> requiredType)public < T > T queryForObject(String sql, SqlParameterSource paramSource, Class<T> requiredType)

Integer count = template.queryForObject(\"select count(*) from student\", new HashMap<>(), Integer.class);String name = template.queryForObject( \"select name from student where home_address  limit 1 \", EmptySqlParameterSource.INSTANCE, String.class); 

返回 (多行)单列 数据

public < T> List< T> queryForList(String sql, Map<String, ?> paramMap, Class< T > elementType)public < T> List< T> queryForList(String sql, SqlParameterSource paramSource, Class< T> elementType)

List< String> namelist = template.queryForList(\"select name from student\", new HashMap<>(), String.class);

返回单行数据

public < T> T queryForObject(String sql, Map< String, ?> paramMap, RowMapper< T>rowMapper)public < T> T queryForObject(String sql, SqlParameterSource paramSource, RowMapper< T> rowMapper)

Student  stu = template.queryForObject(                \"select * from student limit 1\", new HashMap<>(), new BeanPropertyRowMapper<Student>(Student.class));//BeanPropertyRowMapper会把下划线转化为驼峰属性//结果对象可比实际返回字段多或者少

注意:这两个API也可以使用SingleColumnRowMapper返回单行单列数据

String name = template.queryForObject(                \"select name from student limit 1\", EmptySqlParameterSource.INSTANCE, new SingleColumnRowMapper<>(String.class));

返回Map形式的单行数据

public Map< String, Object> queryForMap(String sql, Map< String, ?> paramMap)public Map< String, Object> queryForMap(String sql, SqlParameterSource paramSource)

Map< String, Object> studentMap = template.queryForMap(\"select * from student limit 1\", new HashMap<>());

注意:queryForMap这个方法要求结果必须是有数据的,否则会报错。

返回多行数据

public < T> List< T> query(String sql, Map< String, ?> paramMap, RowMapper< T> rowMapper)public < T> List< T> query(String sql, SqlParameterSource paramSource, RowMapper< T> rowMapper)public < T> List< T> query(String sql, RowMapper< T> rowMapper)

List< Student> studentList = template.query(                \"select * from student\",                  new BeanPropertyRowMapper<>(Student.class));     

同理,也可以使用SingleColumnRowMapper返回单行列表List< String>,List< Integer>等。

返回多行数据(Map)

public List< Map< String, Object>> queryForList(String sql, Map< String, ?> paramMap)public List< Map< String, Object>> queryForList(String sql, SqlParameterSource paramSource)

List<Map<String, Object>> mapList = template.queryForList(                \"select * from student\", new HashMap<>());

插入/修改/删除数据,使用updateXXX方法

使用Map作为参数

int update(String sql, Map<String, ?> paramMap)

Map<String, Object> paramMap = new HashMap<>();paramMap.put(\"id\", UUID.randomUUID().toString());paramMap.put(\"name\", \"小明\");paramMap.put(\"age\", 33);paramMap.put(\"homeAddress\", \"乐山\");paramMap.put(\"birthday\", new Date());template.update(      \"insert into student(id,name,age,home_address,birthday) values (:id,:name,:age,:homeAddress,:birthday)\",     paramMap);

使用SqlParameterSource作为参数

int update(String sql, SqlParameterSource paramSource)

//使用 BeanPropertySqlParameterSource作为参数StudentDTO dto=new StudentDTO();//这个DTO为传入数据dto.setId(UUID.randomUUID().toString());dto.setName(\"小红\");dto.setHomeAddress(\"成都\");//------------------------------template.update(\"insert into student(id,name,home_address) values (:id,:name,:homeAddress)\",                new BeanPropertySqlParameterSource(dto));//使用MapSqlParameterSource 作为参数MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource()        .addValue(\"id\", UUID.randomUUID().toString())        .addValue(\"name\", \"小王\")        .addValue(\"homeAddress\", \"美国\");template.update(\"insert into student(id,name,home_address) values                       (:id,:name,:homeAddress)\",mapSqlParameterSource);

开发中尽量使用NamedParameterJdbcTemplate代替JdbcTemplate,如果想使用JdbcTemplate,也可以通过NamedParameterJdbcTemplate#getJdbcOperations()获取

不建议使用查询结构为Map的API

(0)
小多多的头像小多多创始人

相关推荐

发表回复

登录后才能评论