MyBatis常用工具类三-使用SqlRunner操作数据库
ztj100 2025-05-30 19:04 9 浏览 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对象。
- 上一篇:爆肝2W字梳理50道计算机网络必问面试题
- 下一篇:Java核心知识3:异常机制详解
相关推荐
- Spring IoC Container 原理解析
-
IoC、DI基础概念关于IoC和DI大家都不陌生,我们直接上martinfowler的原文,里面已经有DI的例子和spring的使用示例...
- SQL注入:程序员亲手打开的潘多拉魔盒,如何彻底封印它?
-
一、现象:当你的数据库开始"说话",灾难就来了场景还原:...
- Java核心知识3:异常机制详解
-
1什么是异常异常是指程序在运行过程中发生的,由于外部问题导致的运行异常事件,如:文件找不到、网络连接失败、空指针、非法参数等。异常是一个事件,它发生在程序运行期间,且中断程序的运行。...
- MyBatis常用工具类三-使用SqlRunner操作数据库
-
MyBatis中提供了一个非常实用的、用于操作数据库的SqlRunner工具类,该类对JDBC做了很好的封装,结合SQL工具类,能够很方便地通过Java代码执行SQL语句并检索SQL执行结果。SqlR...
- 爆肝2W字梳理50道计算机网络必问面试题
-
1.说说HTTP常用的状态码及其含义?思路:这道面试题主要考察候选人,是否掌握HTTP状态码这个基础知识点。...
- SpringBoot整合Vue3实现发送邮箱验证码功能
-
1.效果演示2.思维导图...
- 最全JAVA面试题及答案(200+)
-
Java基础1.JDK和JRE有什么区别?JDK:JavaDevelopmentKit的简称,Java开发工具包,提供了Java的开发环境和运行环境。JRE:JavaRunti...
- Java程序员找工作翻车现场!你的项目描述踩了这几个坑?
-
Java程序员找工作翻车现场!你的项目描述踩了这几个坑?噼里啪啦敲了三年代码,简历一投石沉大海?兄弟,问题可能出在项目描述上!知道为什么面试官看你的项目像看天书吗?因为你写了三个致命雷区:第一,把项目...
- 2020最新整理JAVA面试题附答案,包含19个模块共208道面试题
-
包含的模块:本文分为十九个模块,分别是:Java基础、容器、多线程、反射、对象拷贝、JavaWeb、异常、网络、设计模式、Spring/SpringMVC、SpringBoot/Spring...
- 底层原理深度解析:equals() 与 == 的 JVM 级运作机制
-
作为Java开发者,你是否曾在集合操作时遇到过对象比较的诡异问题?是否在使用HashMap时发现对象丢失?这些问题往往源于对equals()和==的误解,以及实体类中这两个方法的不当实...
- 雪花算法,什么情况下发生 ID 冲突?
-
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的...
- 50个Java编程技巧,免费送给大家
-
一、语法类技巧1.1.使用三元表达式普通:...
- 如何规划一个合理的JAVA项目工程结构
-
由于阿里Java开发手册对于工程结构的描述仅限于1、2节简单的概述,不能满足多样的实际需求,本文根据多个项目中工程的实践,分享一种较为合理实用的工程结构。工程结构的原则有依据、实用。有依据的含义是指做...
- Java 编程技巧之单元测试用例编写流程
-
温馨提示:本文较长,同学们可收藏后再看:)前言...
- MyBatis核心源码解读:SQL执行流程的奇妙之旅
-
MyBatis核心源码解读:SQL执行流程的奇妙之旅大家好呀!今天咱们要来一场既烧脑又有趣的旅程——探索MyBatis这个强大框架的核心秘密。你知道吗?当你在项目里轻轻松松写一句“select*f...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)