当前位置: 首页 > 工具软件 > nutz-sqltpl > 使用案例 >

Nutz自定义SQL

刘英彦
2023-12-01

Nutz自定义SQL

创建SQL对象

用户可以硬编码 SQL 语句,比如

Sql sql = Sqls.create("DELETE FROM t_abc WHERE name='Peter'");

支持占位符的书写方式,比如

Sql sql = Sqls.create("DELETE FROM $table WHERE name=@name");
sql.vars().set("table","t_abc");
sql.params().set("name","Peter");
// 连写
sql.setVar("table","t_abc").setVar(...);
sql.setParam("name","Peter").setParam(...);
  • $table 将会被替换成 t_abc
  • @name 将会被替换成 ?,用来创建 PreparedStatement

Sql 的逃逸字符

有些时候,有的朋友给出的 SQL 包括特殊字符 ‘@’ 或者 ‘$’,比如

Sql sql = Sqls.create("INSERT INTO t_usr (name,email) VALUES('XiaoMing','xiaoming@163.com');"

这个时候,因为有关键字 ‘@’,所以 SQL 不能被正确解析,因为你的本意是给一个 ‘xiaoming@163.com’ 这个字符串。但是 Nutz.Dao 却认为这个是个语句参数。

这时候你可以使用逃逸字符

Sql sql = Sqls.create("INSERT INTO t_usr (name,email) VALUES('XiaoMing','xiaoming@@163.com');"

  • 输入 “@@” 表示一个 ‘@’
  • 输入 "$ " 表 示 一 个 ′ " 表示一个 ' "

执行 Sql 对象

UPDATE, DELETE, INSERT

public void demoSql(Dao dao){
    Sql sql = Sqls.create("SELECT name FROM t_abc WHERE name LIKE @name");
    sql.params().set("name", "A%");
    dao.execute(sql);
}

SELECT 是需要返回 结果的,于是,就需要你设置回调

在调用 dao.execute 方法前调用 sql.forceExecQuery 方法来强制让 nutz 用 select 方式运行该 sql 语句

List<String> demoSql(Dao dao) {
    Sql sql = Sqls.create("SELECT name FROM t_abc WHERE name LIKE @name");
    sql.params().set("name", "A%");
    sql.setCallback(new SqlCallback() {
        public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
            List<String> list = new LinkedList<String>();
            while (rs.next())
                list.add(rs.getString("name"));
            return list;
        }
    });
    dao.execute(sql);
    return sql.getList(String.class);
    // Nutz内置了大量回调, 请查看Sqls.callback的属性
}

总结一下:

  1. 回调对象实现接口 org.nutz.dao.sql.SqlCallback,事实上,就像上例所示,这种场景非常适合使用匿名类。
  2. 你的回调函数的返回值会存放在 Sql 对象中
  3. 调用 sql.getResult() 可以直接返回这个对象
  4. sql.getList() 以及 sql.getObject() 方法会泛型安全的替你转型
    • 如果你的对象类型符合要求,则直接返回,否则会通过 Nutz.Castors 替你转换。
    • 对于 getList(),泛型参数用来描述集合内部元素的类型
  5. sql.getInt() 会安全的替你将结果转成 int,如果它可以被转成 int 的话,以下是我能想到的列表:
    • 字符串
    • 各种数字类型
    • 字符
    • 布尔类型

获取一个列表的回调

只要你保证你的 Master 类声明了 @Table 并且每个字段上的 @Column 可以同你的 ResultSet 配置起来 那么,上面的代码可以很方便的帮你获取一个 List<Master>

@Test
	public void sql1() {
		//创建SQL语句
		Sql sql = Sqls.create("select * from student where name='小明'");
		//获取回调
		Sql setCallback = sql.setCallback(Sqls.callback.entities());
		//重写父接口返回值    getEntity获取实体描述, 其中包含了Java Pojo<-->数据库的全部映射信息
		Sql setEntity = sql.setEntity(dao.getEntity(Student.class));		
		//执行SQL语句
		dao.execute(sql);
		List<Student> list = sql.getList(Student.class);		
	}

批量执行

在 Nutz 1.b.38 之后的版本,自定义 SQL 可以支持批量操作

Sql sql = Sqls.create("UPDATE t_pet SET name=@name WHERE id=@id");
sql.params().set("name","XiaoBai").set("id",4);
sql.addBatch();//结束一个SQL
sql.params().set("name","XiaoHei").set("id",5);
sql.addBatch();//结束一个SQL
dao.execute(sql);

加载 SQL 文件

如何使用上述的 SQL 文件呢,可以将数个 SQL 文件加载到 Dao 对象中。在之后,只要得到 Dao 的对象,可以使用 dao.sqls() 方法获得 org.nutz.dao.SqlManager 接口,从这个接口中你就可以获得你预先定义好的 Sql 对象了。

对于 Dao 接口的默认实现, org.nutz.dao.impl.NutDao,提供两个方法,一个是通过构造函数,另一个是 setter 函数。

在构造时加载

(示意代码,新建NutDao属于重量级操作,应使用单例或Ioc模式)

Dao dao = new NutDao(datasource,new FileSqlManager("demo/sqls/all.sqls"));
System.out.println(dao.sqls().count());

在构造之后的任何时加载

(示意代码,新建NutDao属于重量级操作,应使用单例或Ioc模式)

Dao dao = new NutDao(datasource);
((NutDao)dao).setSqlManager(new FileSqlManager("demo/sqls/all.sqls"));
System.out.println(dao.sqls().count());

条件变量占位符

特殊的占位符 – $condition

Sql sql = Sqls.create("SELECT name FROM t_pet $condition");
sql.setCondition(Cnd.where("id", ">", 35)).setCallback(new SqlCallback() {
    public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
        List<String> list = new LinkedList<String>();
        while (rs.next())
            list.add(rs.getString("name"));
        return list;
    }
});
dao.execute(sql);
for (String name : sql.getList(String.class))
    System.out.println(name);

获取实体的回调

Sql sql = Sqls.create("SELECT * FROM student $condition");
	    sql.setCallback(Sqls.callback.entity());
	    Entity<Student> entity = dao.getEntity(Student.class);
	    sql.setEntity(entity).setCondition(Cnd.wrap("id=1"));
	    dao.execute(sql);
	    Student object = sql.getObject(Student.class);
	    System.out.println("object==========="+object);

为了方便起见,你可以直接使用 Sqls.fetch 来创建你的 Sql 对象,这个函数会自动为你的 Sql 设置获取实体的回调

Sql sql = Sqls.fetchEntity("SELECT * FROM student $condition");
	    Entity<Student> entity = dao.getEntity(Student.class);
	    sql.setEntity(entity).setCondition(Cnd.wrap("id=1"));
	    dao.execute(sql);
	    Student object = sql.getObject(Student.class);
	    System.out.println("object==========="+object);

查询实体的回调

Sql sql = Sqls.create("SELECT * FROM student $condition");
	    sql.setCallback(Sqls.callback.entities());
	    Entity<Student> entity = dao.getEntity(Student.class);
	    sql.setEntity(entity).setCondition(Cnd.wrap("id=1"));
	    dao.execute(sql);
	    List<Student> list = sql.getList(Student.class);
	    System.out.println("list==========="+list);

多条件占位符

(1.b.53开始提供)

任意变量的值类型为Condition时,均自动识别为条件占位符

Sql sql = Sqls.create("select * from user where id in (select id from vips $vip_cnd ) and name in (select name from girls $girl_cnd )");
    sql.setVar("vip_cnd", Cnd.where("level", ">", 5));
    sql.setVar("girl_cnd", Cnd.where("age", "<", 30));
    sql.setCallback(Sqls.callback.records());
    dao.execute(sql);

注意事项: 如果调用过setEntity,那么对应的Cnd会进行属性名-字段名映射

练习

查询所有

@Autowired
private Dao dao;
@Override
public List<Goods_detail> DetailfindAll() {
    List<Goods_detail> query = dao.query(Goods_detail.class, null);
    return query;
}

通过ID查询

@Override
public Goods_detail DetailfindById(Long id) {
    Sql sql = Sqls.create("select * from goods_detail $condition");
    sql.setCallback(Sqls.callback.entity());    
    sql.setEntity(dao.getEntity(Goods_detail.class)).setCondition(Cnd.wrap("id="+id));
    dao.execute(sql);
    Goods_detail object = sql.getObject(Goods_detail.class);
    System.out.println("object==========="+object);
    
    return object;
}

多表查询

结合查询的条件创建的实体类Goods

@Override
public List<Goods> GoodsfindAll() {
    //创建SQL语句
    Sql sql = Sqls.create("select d.`id`,d.`sortId`,d.`name`,d.`address`,d.`price`,d.`createDate`,d.`remaining`,s.`name` as sname from goods_detail d,goods_sort s where d.`sortId`=s.`id`");

    //获取回调
    Sql setCallback = sql.setCallback(Sqls.callback.entities());
    //重写父接口返回值    getEntity获取实体描述, 其中包含了Java Pojo<-->数据库的全部映射信息
    Sql setEntity = sql.setEntity(dao.getEntity(Goods.class));
    //执行SQL语句
    dao.execute(sql);
    List<Goods> list = sql.getList(Goods.class);
    System.out.println(list);
    return list;
}

insert插入

@Override
public void DetailInsert(Goods_detail goods_detail) {
    Goods_detail insert = dao.insert(goods_detail);
    System.out.println("insert============="+insert);
}

Delete删除

@Override
public void DetailDelete(Long id) {
   int delete = dao.delete(Goods_detail.class,id);
}

Update更新

@Override
public void DetailUpeate(Goods_detail goods_detail) {
    //根据需要修改的id获取当前对象信息
    Goods_detail detail = dao.fetch(Goods_detail.class,goods_detail.getId());
    detail.setName(goods_detail.getName());
    /**
	  * 不管更新一条还是更新一个对象,那些没有传入数据的字段值是不会改变的
	  */
    //dao.update(detail,"^name$");//只更新一条  正则表达式^name$
    dao.update(detail);//或者更新一个对象的数据
}
 类似资料: