SQL 类

MyBatis 提供了一个 SQL 工具类,使用这个工具类,我们可以很方便在 Java 代码动态构建 SQL 语句

String newSql = new SQL() ({
SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL NAME");
SELECT("P.LAST NAME, P.CREATED ON, P.UPDATED ON");
FROM("PERSON P");
FROM("ACCOUNT A");
INNER JOIN("DEPARTMENT D ON DID=P.DEPARTMENT ID");
INNER JOIN("COMPANY C On D.COMPANY ID=C.ID");
WHERE("P.ID = A.ID");
WHERE("P.FIRST NAME like ?");
OR();
WHERE("P.LAST NAME like ?");
GROUP BY("P.ID");
HAVING("P.LAST_NAME like ?");
OR();
HAVING("P.FIRST NAME like ?");
ORDER BY("P.ID");
ORDER BY("P.FULL NAME");
}}.tostring();

如上面的代码所示,创建了一个匿名的 SQL 类的子类,在匿名子类的初始化代码块中,调用 SELECT()、FROM() 等方法构建 SQL 语句,这种方式能够很好地避免字符串拼接过程中缺少空格或者偶然间重复出现的 AND 关键字导致的 SOL 语句不正确

除了 SELECT 语句外,SQL 工具类也可以用作构建 UPDATE、INSERT 等语句

@Test
public void testInsertSql() {
String insertSql = new SQL().
INSERT INTO("PERSON").
VALUES("ID, FIRST NAME","#{id}, #{firstName}").
VALUES("LAST NAME","#(lastName}").toString();
System.out.println(insertSal);
} @Test
public void testDeleteSql() {
String deleteSql= new SQL() {{
DELETE FROM("PERSON");
WHERE("ID = #{id)");
}}.toString();
System.out.println(deleteql);
} @Test
public void testUpdateSql() {
String updateSql= new SQL() {{
UPDATE("PERSON");
SET("FIRST NAME = #{firstName}");
WHERE("ID = #{id}");
}}.toString();
System.out.println(updateSql);
}

使用 SQL 工具类的另一个好处是可以很方便地在 Java 代码中根据条件动态地拼接 SQL 语句

public String selectPerson(final String id, final String firstName, final String lastName) {
return new SQL() {{
SELECT("P.ID, P.USERNAME, P.PASSWORD");
SELECT("P.FIRST_NAME, P.LAST NAME");
FROM("PERSON P");
if (id != null) {
WHERE("P.ID=#{id}");
}
if (firstName != null) {
WHERE("P.FIRST_NAME=#{firstName}");
}
if (lastName != null) {
WHERE("P.LAST_NAME=#{lastName}");
}
}}.toString();
}

ScriptRunner

该工具类用于读取脚本文件中的 SQL 语句并执行

public void testscriptRunner() {
try {
Connection connection=DriverManager.getConnection("jdbc:hsqldb:mem:mybatis","sa","");
Scriptrunner scriptRunnermnew ScriptRunner(connection):
scriptrunner.runScript(Resources.getResourceAsReader("create-table.sql"))
} catch (Exception e) {
e.printstackTrace();
}
}

如上面的代码所示,ScriptRunner 工具类的构造方法需要一个 java.sql.Connection 对象作为参数。创建 ScriptRunner 对象后,调用该对象的 runScript 方法即可,该方法接收一个读取 SQL 脚本文件的 Reader 对象作为参数

ScriptRunner 工具类中提供了一些属性,用于控制执行 SQL 脚本的一些行为,代码如下;

public class ScriptRunner{
// SQL异常是否中断程序执行
private boolean stopOnError;
// 是否抛出 SQLWarning 警告
private boolean throwWarning;
//是否自动提交
private boolean autoCommit;
// 属性为 true 时,批量执行文件中的 SQL 语句
//为false时逐条执行 sQL 语句,默认情况下,SQL语句以分号分割
private boolean sendfullScript;
//是否去除Windows系统换行符中的\r
private boolean removecrs;
//设置statement属性是否支持转义处理
private boolean escapeProcessing=true;
// 日志输出位置,默认标准输入输出,即控制台
private PrintWriter logWriter=new PrintWriter(System.out);
// 错误日志输出位置,默认控制台
private PrintWriter errorLoqWriter =new PrintWriter(System.err);
// 脚本文件中 SOL 语句的分隔符,默认为分号
private String delimiter= DEFAULT_DELIMITER;
// 是否支持 SOL 语句分割符,单独占一行
private boolean fullLineDelimiter;
...
}

我们可以直接调用这些属性对应的 Setter 方法来控制 ScriptRunner 工具类执行 SQL 脚本的行为

SqlRunner

MyBatis 提供了一个非常实用的、用于操作数据库的 SqlRunner 工具类,该类对 JDBC 做了很好的封装,结合 SQL 工具类,能够很方便地通过 Java 代码执行 SQL 语句并检索 SQL 执行结果

SglRunner 类提供了几个操作数据库的方法,分别说明如下:

  • SqlRunner#closeConnection: 用于关闭 Connection 对象
  • SqlRunner#selectOne(String sql, Object… args):执行 SELECT 语句,SQL 语句中可以使用占位符,如果 SOL 中包含占位符,则可变参数用于为参数占位符赋值,该方法只返回一条记录,若查询结果行数不等于一,则会抛出 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 工具类的使用案例,代码如下:

@Test
public void testselectOne() throws SQLException {
SqlRunner sqlRunner=new SqlRunner(connection)
String gryUserSql = 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();
sqlRunner.insert(insertUserSql,createTime,"Jane","test","18700000000" "J");
}

MetaObject

MetaObject 是 MyBatis 中的反射工具类,该工具类在 MyBati s源码中出现的频率非常高。使用 MetaObject 工具类,我们可以很优雅地获取和设置对象的属性值

使用 MetaObject 工具类获取 User 对象的属性信息,案例代码如下:

@Test
public void testMetaObject() {
List<order> orders= new ArrayList()(
add(new Order("order20171024010246","《MyBatis源码深度解析》图书"));
add(new Order("order20171024010248","《AngularJs入门与进阶》图书"));
};
User user = new User(orders,"江荣波",3);
MetaObject metaObject = SystemMetaObject.forObject(user);
// 获取第一笔订单的商品名称
System.out.println(metaObject.getValue("orders[0].goodsName"));
// 获取第二笔订单的商品名称
System.out.println(metaObject.getvalue("orders[1].goodsName"));
// 为属性设置值
metaObject.setValue("orders[1].orderNo","order20181113010139");
// 判断 User 对象是否有 orderNo 属性
System.out.println("是否有orderNo属性且orderNo属性有对应的Getter方法:" + metaObject.hasGetter("orderNo"));
// 判断 User 对象是否有 name 属性
System.out.println("是否有name属性且name 属性有对应的Getter方法:" + metaObject.hasGetter("name"));
}

MetaClass

MetaClass 是 MyBatis 中的反射工具类,与 MetaOjbect 不同的是,MetaObject 用于获取和设置对象的属性值,而 MetaClass 则用于获取类相关的信息

@Test
public void testMetaClass() {
MetaClass metaClass =MetaClass.forClass(Orderclass,newDefaultReflectorFactory());
// 获取所有有 Getter 方法的属性名
String[] getterNames = metaClass.getGetterNames();
System.out.println(JSON.toJSONString(getterNames));
// 是否有默认构造方法
System.out.println("是否有默认构造方法:" + metaClass.hasDefaultConstructor());
// 某属性是否有对应的Getter/Setter方法
System.out.printIn("orderNo属性是否有对应的Getter 方法:" + metaClass.hasGetter("orderNo"));
System.out.println("orderNo属性是否有对应的Setter方法:" + metaClass.hasSetter("orderNo"));
System.out.println("orderNo属性类型:" + metaClass.getGetterType("orderNo"));
}

ObjectFactory

ObjectFactory 是 MyBatis 中的对象工厂,MyBatis 每次创建 Mapper 映射结果对象的新实例时,都会使用一个对象工厂实例来完成。ObjectFactory 接口只有一个默认的实现,即 DefaultObjectFactory,默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化

public class ObjectFactoryExample {
@Test
public void testObjectFactory() {
ObjectFactory objectFactory = new DefaultObjectFactory();
List<Integer> list = objectFactory.create(List.class);
Map<String, String> map = objectFactory.create(Map.class);
list.addAll(Arrays.asList(1. 23));
map.put("test","test");
System.out.printin(list);
System.out.println(map);
}
}

MyBatis 中使用 ObjectFactory 实例创建 Mapper 映射结果对象的目的是什么呢?实际上,这是 MyBatis 提供的一种扩展机制。有些情况下,在得到映射结果之前我们需要处理一些逻辑,或者在执行该类的有参构造方法时,在传入参数之前,要对参数进行一些处理,这时我们可以通过自定义 ObjectFactory 来实现。下面是一个自定义 ObjectFactory 的案例,代码如下:

public class CustomObjectfactory extends Defaultobjectfactory{

  @Override
public object create(Class type){
if(type.equals(User.class)) {
//实例化User类
User user=(User)super.create(type);
user.setUuid(UUID.randomUUID().toString());
return user;
}
return super.create(type);
}
}

如上面的代码所示,自定义一个 ObjectFactory 非常简单,我们可以继承 DefaultObjectFactory,然后重写 create 方法即可。自定义 ObjectFactory 后,还需要在MyBatis 主配置文件中通过 标签配置自定义的 ObjectFactory,具体如下:

<objectfactory type="com.blog4java.mybatis.objectfactory.CustomobjectFactory">
<property name="someProperty" value="10"/>
</objectfactory>

ProxyFactory

ProxyFactory 是 MyBatis 的代理工厂,主要用于创建动态代理对象,ProxyFactory接口有两个不同的实现,分别为 CglibProxyFactory 和 JavassistProxyFactory。从实现类的名称可以看出,MyBatis 支持两种动态代理策略,分别为 Cglib 和 Javassist 动态代理。ProxyFactory主要用于实现 MyBatis 的懒加载功能。当开启懒加载后,MyBatis 创建 Mapper 映射结果对象后,会通过 ProxyFactory 创建映射结果对象的代理对象。当我们调用代理对象的 Getter 方法获取数据时,会执行 CglibProxyFactory 或 JavassistProxyFactory 中定义的拦截逻辑,然后执行一次额外的查询

下面是使用 JavassistProxyFactory 创建动态代理对象的案例,代码如下:

public class ProxyFactoryExample {

  @Data
@AllArgsConstructor
private static class Order {
private String orderNo;
private String goodsName;
} @Test
public void testProxyFactory() {
// 创建 ProxyFactory对象
ProxyFactory proxyFactory =new JavassistProxyFactory();
Order order = new Order("gn20170123","《MyBatis源码深度解析》图书");
ObjectFactory objectFactory=new DefaultObjectFactory();
//调用ProxyFactory对象的createProxy()方法创建代理对象
Object proxyOrder=proxyFactory.createProxy(order,
mock(ResultLoaderMap.class),
mock(Configuration.class),
objectfactory,
Arrays.asList(String.class,String.class),
Arrays.asList(order.getorderNo(),order.getGoodsName()));
System.out.println(proxyOrder.getClass());
System.out.println(((Order)proxyOrder).getGoodsName());
}
}

MyBatis 常用工具类的更多相关文章

  1. Maven基础&&Spring框架阶段常用工具类整理

    常用工具类 1.密码加密工具类: package com.itheima.utils; import java.security.MessageDigest; import sun.misc.BASE ...

  2. js常用工具类.

    一些js的工具类 复制代码 /** * Created by sevennight on 15-1-31. * js常用工具类 */ /** * 方法作用:[格式化时间] * 使用方法 * 示例: * ...

  3. IOS开发--常用工具类收集整理(Objective-C)(持续更新)

    前言:整理和收集了IOS项目开发常用的工具类,最后也给出了源码下载链接. 这些可复用的工具,一定会给你实际项目开发工作锦上添花,会给你带来大大的工作效率. 重复造轮子的事情,除却自我多练习编码之外,就 ...

  4. Apache Commons 常用工具类整理

    其实一直都在使用常用工具类,只是从没去整理过,今天空了把一些常用的整理一下吧 怎么使用的一看就明白,另外还有注释,最后的使用pom引入的jar包 public class ApacheCommonsT ...

  5. Android 常用工具类之SPUtil,可以修改默认sp文件的路径

    参考: 1. 利用Java反射机制改变SharedPreferences存储路径    Singleton1900 2. Android快速开发系列 10个常用工具类 Hongyang import ...

  6. 封装一个简单好用的打印Log的工具类And快速开发系列 10个常用工具类

    快速开发系列 10个常用工具类 http://blog.csdn.net/lmj623565791/article/details/38965311 ------------------------- ...

  7. javaweb常用工具类及配置文件备份

    Javaweb常用工具类及配置文件备份   做一个代码备份,以后常用到的. hibernate工具类备份 package com.dly.service; /*  * hibernate获取sessi ...

  8. [C#] 常用工具类——直接在浏览器输出数据

    /// <summary> /// <para> </para> /// 常用工具类——直接在浏览器输出数据 /// <para> ---------- ...

  9. [C#] 常用工具类——加密解密类

    using System; using System.Configuration; using System.Collections.Generic; using System.Text; using ...

  10. C#常用工具类——Excel操作类

    /// 常用工具类——Excel操作类 /// <para> ------------------------------------------------</para> / ...

随机推荐

  1. Jquery实现复选框的选中和取消

    复选框的选中与取消 我在网上看了好多关于这个问题的解答,好多都是一两个按钮的触发事件,有的甚至没有任何效果,经过自己的调试发现这个方法好用一点: 首先我在页面上添加了这样一个复选框 我的复选框是动态加 ...

  2. 简单记录下RestTemplate使用方法

    1.设置get方法 ResponseEntity<JSONObject> responseEntity= restTemplate.getForEntity(url,JSONObject. ...

  3. 深度学习-09(目标检测:Object Detection)

    文章目录 目标检测(Object Detection) 一 .基本概念 1. 什么是目标检测 2. 目标检测的核心问题 3. 目标检测算法分类 4. 目标检测应用 目标检测原理 1.候选区域产生 1 ...

  4. Pyathon If条件测试

    if条件测试 # 案例 cars = ['audi','bmw','subaru','toyota'] for car in cars: if car =='bmw': print(car.upper ...

  5. 2022-11-11:设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素。 实现 MaxStack 类: MaxStack() 初始化栈对象 void push(int x) 将元素 x 压

    2022-11-11:设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素. 实现 MaxStack 类: MaxStack() 初始化栈对象 void push(int x) 将元素 x 压 ...

  6. 2022-09-08:以下go语言代码输出什么?A:5 66;B:5 88;C:7 88;D:以上都不对。 package main func main() { var x = []int{4:

    2022-09-08:以下go语言代码输出什么?A:5 66:B:5 88:C:7 88:D:以上都不对. package main func main() { var x = []int{4:44, ...

  7. 2021-12-23:每日温度。 请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。 示例 1: 输

    2021-12-23:每日温度. 请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度.如果气温在这之后都不会升高,请在该位置用 0 来代替. 示例 1: 输入 ...

  8. TokenObtainPairView

    TokenObtainPairView是由Django REST framework的SimpleJWT库提供的视图.它用于生成JSON Web Token(JWT)

  9. SQL Server2019 删除列字段

    命令: 有默认值时用:alter table 表名 DROP  约束 alter table 表名 DROP COLUMN 列名 例如: alter table LJEL005H DROP COLUM ...

  10. 在windows下安装elk

    一.下载elasticsearch-5.1.1 cd D:\bigdata\elasticsearch-5.1.1\bin elasticsearch-service.bat cmd 运行 servi ...