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)来处理结果集,用户必须处理整个结果集;
@test
public 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,当然可以转换为其他类。
@test
public 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),能将结果集的行转换为需要的形式。
@test
public 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
@test
public 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
下一篇: 键盘记录工具开源(电脑键盘密码记录器)
推荐阅读
-
template标签是什么意思(vue的template用法)
-
Vue是怎么渲染template内的标签内容的
-
html noscript标签是什么意思?关于noscript标签的用法你了解多少?
-
html form标签的action属性是什么意思?又有哪些用法?(附实例)
-
html5 section标签是什么意思?html5 section标签的用法总结
-
html tfoot标签是什么意思?这里有html tfoot标签的定义和用法实例
-
html optgroup标签是什么意思?关于html optgroup标签的用法和属性实例解析
-
HTML中的caption属性是什么意思?caption标签在HTML中的用法(附实例)
-
HTML5中footer标签的用法你知道吗?,HTML5中的footer标签是什么意思?
-
html applet标签是什么意思?html applet标签的用法详解