MyBatis常用工具类三-使用SqlRunner操作数据库
lipiwang 2025-05-27 15:48 5 浏览 0 评论
MyBatis中提供了一个非常实用的、用于操作数据库的SqlRunner工具类,该类对JDBC做了很好的封装,结合SQL工具类,能够很方便地通过Java代码执行SQL语句并检索SQL执行结果。
SqlRunner类提供了几个操作数据库的方法,分别说明如下。
SqlRunner#closeConnection():用于关闭Connection对象。
SqlRunner#selectOne(String sql, Object… args):执行SELECT语句,SQL语句中可以使用占位符,如果SQL中包含占位符,则可变参数用于为参数占位符赋值,该方法只返回一条记录。若查询结果行数不等于一,则会抛出SQLException异常。
SqlRunner#selectAll(String sql, Object… args):该方法和selectOne()方法的作用相同,只不过该方法可以返回多条记录,方法返回值是一个List对象,List中包含多个Map对象,每个Map对象对应数据库中的一行记录。
SqlRunner#insert(String sql, Object… args):执行一条INSERT语句,插入一条记录。
SqlRunner#update(String sql, Object… args):更新若干条记录。
SqlRunner#delete(String sql, Object… args):删除若干条记录。
SqlRunner#run(String sql):执行任意一条SQL语句,最好为DDL语句。
接下来我们来看一下SqlRunner工具类的使用案例,代码如下:
public class SqlRunnerExample {
Connection connection = null;
@Before
public void initTable() throws SQLException, IOException {
connection = DriverManager.getConnection("jdbc:hsqldb:mem:mybatis",
"sa", "");
ScriptRunner scriptRunner = new ScriptRunner(connection);
scriptRunner.setLogWriter(null);
scriptRunner.runScript(Resources.getResourceAsReader("create-table.sql"));
scriptRunner.runScript(Resources.getResourceAsReader("init-data.sql"));
}
@Test
public void testSelectOne() throws SQLException {
SqlRunner sqlRunner = new SqlRunner(connection);
String qryUserSql = new SQL() {{
SELECT("*");
FROM("user");
WHERE("id = ?");
}}.toString();
Map<String, Object> resultMap = sqlRunner.selectOne(qryUserSql, Integer.valueOf(1));
System.out.println(JSON.toJSONString(resultMap));
}
@Test
public void testDelete() throws SQLException {
SqlRunner sqlRunner = new SqlRunner(connection);
String deleteUserSql = new SQL(){{
DELETE_FROM("user");
WHERE("id = ?");
}}.toString();
sqlRunner.delete(deleteUserSql, Integer.valueOf(1));
}
@Test
public void testUpdate() throws SQLException {
SqlRunner sqlRunner = new SqlRunner(connection);
String updateUserSql = new SQL(){{
UPDATE("user");
SET("nick_name = ?");
WHERE("id = ?");
}}.toString();
sqlRunner.update(updateUserSql, "Jane", Integer.valueOf(1));
}
@Test
public void testInsert() throws SQLException {
SqlRunner sqlRunner = new SqlRunner(connection);
String insertUserSql = new SQL(){{
INSERT_INTO("user");
INTO_COLUMNS("create_time,name,password,phone,nick_name");
INTO_VALUES("?,?,?,?,?");
}}.toString();
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
sqlRunner.insert(insertUserSql,createTime,"Jane","test","18700000000","J");
}
@After
public void closeConnection() {
IOUtils.closeQuietly(connection);
}
}
除了查询外,我们还可以使用SqlRunner完成数据库的增删改操作。
熟悉了SqlRunner工具类的使用后,接下来我们了解一下SqlRunner工具类的实现。以selectAll()方法为例,该方法代码如下:
/*
* Executes a SELECT statement that returns multiple rows.
*
* @param sql The SQL
* @param args The arguments to be set on the statement.
* @return The list of rows expected.
* @throws SQLException If statement preparation or execution fails
*/
public List<Map<String, Object>> selectAll(String sql, Object... args) throws SQLException {
PreparedStatement ps = connection.prepareStatement(sql);
try {
setParameters(ps, args);
ResultSet rs = ps.executeQuery();
return getResults(rs);
} finally {
try {
ps.close();
} catch (SQLException e) {
//ignore
}
}
}
如上面的代码所示,SqlRunner工具类的selectAll()逻辑如下:
(1)调用Connection对象的prepareStatement()方法获取PreparedStatement对象后,调用setParameters()方法为SQL中的参数占位符赋值。
(2)调用PreparedStatement的executeQuery()方法执行查询操作。
(3)调用getResults()方法,将ResultSet对象转换为List对象,其中List对象中的每个Map对象对应数据库中的一条记录。
接下来我们来看一下setParameters()方法的实现,代码如下:
private void setParameters(PreparedStatement ps, Object... args) throws SQLException {
for (int i = 0, n = args.length; i < n; i++) {
if (args[i] == null) {
throw new SQLException("SqlRunner requires an instance of Null to represent typed null values for JDBC compatibility");
} else if (args[i] instanceof Null) {
((Null) args[i]).getTypeHandler().setParameter(ps, i + 1, null, ((Null) args[i]).getJdbcType());
} else {
TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(args[i].getClass());
if (typeHandler == null) {
throw new SQLException("SqlRunner could not find a TypeHandler instance for " + args[i].getClass());
} else {
typeHandler.setParameter(ps, i + 1, args[i], null);
}
}
}
}
对setParameters()方法的可变参数进行遍历,根据参数类型获取对应的TypeHandler对象,然后调用MyBatis中TypeHandler对象的setParameter()方法为参数占位符赋值。MyBatis中TypeHandler的作用及实现原理将在后面的章节中详细介绍。
最后,我们再来看一下getResultSet()方法处理结果集的过程,代码如下:
private List<Map<String, Object>> getResults(ResultSet rs) throws SQLException {
try {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
List<String> columns = new ArrayList<String>();
List<TypeHandler<?>> typeHandlers = new ArrayList<TypeHandler<?>>();
// 1.获取ResultSetMetaData对象。学习JDBC规范时,我们了解到ResultSetMetaData对象中封装了结果集的元数据信息,
// 包括所有的字段名称及列的数量等信息
ResultSetMetaData rsmd = rs.getMetaData();
for (int i = 0, n = rsmd.getColumnCount(); i < n; i++) {
columns.add(rsmd.getColumnLabel(i + 1));
try {
// 获取所有列的java类型。
// 根据类型获取对应的TypeHandler对象,将TypeHandler对象注册到变量名为typeHandlers的ArrayList对象中
Class<?> type = Resources.classForName(rsmd.getColumnClassName(i + 1));
TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(type);
if (typeHandler == null) {
typeHandler = typeHandlerRegistry.getTypeHandler(Object.class);
}
typeHandlers.add(typeHandler);
} catch (Exception e) {
typeHandlers.add(typeHandlerRegistry.getTypeHandler(Object.class));
}
}
// 遍历ResultSet对象。调用TypeHandler对象的getSesult()方法,
// 将JDBC类型转换为Java类型,然后将ResultSet对象中的记录行转换为Map对象
while (rs.next()) {
Map<String, Object> row = new HashMap<String, Object>();
for (int i = 0, n = columns.size(); i < n; i++) {
String name = columns.get(i);
TypeHandler<?> handler = typeHandlers.get(i);
row.put(name.toUpperCase(Locale.ENGLISH), handler.getResult(rs, name));
}
list.add(row);
}
return list;
} finally {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
// ignore
}
}
}
}
如上面的代码所示,getResultSet()方法处理结果集的过程如下:
(1)获取ResultSetMetaData对象。学习JDBC规范时,我们了解到ResultSetMetaData对象中封装了结果集的元数据信息,包括所有的字段名称及列的数量等信息。getResultSet()方法中通过ResultSetMetaData对象获取所有列的名称。
(2)获取所有列的JDBC类型。根据类型获取对应的TypeHandler对象,将TypeHandler对象注册到变量名为typeHandlers的ArrayList对象中。
(3)遍历ResultSet对象。调用TypeHandler对象的getSesult()方法,将JDBC类型转换为Java类型,然后将ResultSet对象中的记录行转换为Map对象。
- 上一篇:Hive大表rename报错如何处理?
- 下一篇:如何真正写好Golang代码?
相关推荐
- 小程序-如何获取用户表单控件中的值
-
背景在小程序开发中,经常有用到表单,我们往往需要在小程序端获取用户表单输入框中的值(通常用户输入的有:switch,input,checkbox,slider,radio,picker)等,通过触发事...
- Js基础7:表单元素属性
-
一、封装获取元素的方法封装思想——函数封装——代码复用 function get_id(id){ //这个函数是专门来通过id获...
- 泰媒:到泰国曼谷旅游,注意别被嘟嘟车司机坑!
-
据泰国《世界日报》微信公众号报道,近日,一名导游投诉称,3名外籍游客在泰国曼谷搭载嘟嘟车时,被嘟嘟车司机坑。该导游认为嘟嘟车司机坑害外国游客的行为,破坏泰国的旅游形象,希望能以此为戒。当地时间25日上...
- 快速了解JavaScript的表单操作
-
前言在HTML中使用<form>表单元素在JavaScript中对应的是HTMLFormElement类型,而HTMLFormElement继承了HTMLElement接口...
- 10《Vue 入门教程》Vue 双向绑定指令
-
1.前言本小节我们将介绍Vue中数据的双向绑定指令v-model。v-model的学习相对简单。我们可以用v-model指令在表单<input>、<textarea&...
- 手把手教你搭建消防安全答题小程序-实现答题及提交答卷到数据库
-
手把手教你搭建答题活动小程序系列,第一阶段为界面设计篇,分别描写了如何搭建答题小程序界面。第二阶段为功能交互篇。而上两篇文章分别描写了,如何用云开发实现查询题库功能,以及将获取到的题目数据动态更新到答...
- 你还在使用Guava的Lists.newArrayList()吗
-
Guava说起Guava,做Java开发的应该没人不知道吧,毕竟“google出品,必属精品”。虽然应该没有Spring那样让Javaer无法避开,但是其中很多工具类的封装还是让人欲罢不能。而我们今天...
- Mybatis参数传递
-
1.概述Mybatis的sql参数传递就是将接口方法中定义的参数传输到sql中。sql有两种形式,一种是XML格式(Mapper映射器)中的sql;一种是注解方式的sql。常用参数的类型主要包括:基...
- python中的map和filter避坑指南
-
Pythonic的方式使用map和filter列表迭代在python中是非常pythonic的使用方式definc(x):returnx+1>>>list(map...
- 2025 年 Object 和 Map 如何选择?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。1.什么是...
- 如何使用Java读取Excel文件到List>格式
-
引言在开发过程中,我们经常会遇到需要读取Excel文件并将数据转换成Java对象的需求。ApachePOI是一个强大的库,它提供了读取和写入MicrosoftOffice格式文件的功能,包括Exc...
- Nginx L4 stream Solution white list map
-
nginx正向透明代理nginx正向透明代理安全方面的一些限制对于代理而已,有时候可能还不够安全,而且这个是基于4层的,所以想要在http上,或者所谓的http头上做限制还是比较难实现了。所以变...
- Java响应式编程 第五篇 flatMap vs map
-
1作用不同1.2映射?展平?map只执行映射flatMap既执行映射,也执行展平什么叫只能执行映射?我理解是把一个数据执行一个方法,转换成另外一个数据。举个例子:mapper函数把输入的字符...
- Java对象拷贝原理剖析及最佳实践
-
作者:宁海翔1前言对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po、Dto、Do、Vo各个表现层数据的转换,也存在于系统交互如序列化、反序列化。Java对象拷贝分为深拷贝和浅拷贝,目前常用的...
- mybatis手把手教学,希望大家能拿下它
-
目录1.jdbc封装中的问题12.mybatis介绍43.框架搭建41)导包52)配置文件6配置dtd约束73)创建SqlSessionFactory对象94.入门案例91.部门实体...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)