4 Star 2 Fork 1

matrixy / HentaiDAO

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

HentaiDAO

使用全新而又熟悉的方式来编写CRUD

public class Test
{
    public static void main(String[] args) throws Exception
    {
        int sex = 1;
        String name = "test";
        // 查询用户表中,按id倒排,自结果集的第100行起取10行
        // 如果sex值大于0,则参与到where从句中来
        // 如果name不为空字符串,则参与到where从句中来,并且转为like模糊匹配
        List<User> users = select(User.class)
            .where(clause("sex = ?", gtz(sex)).and("name = ?", like(name)))
            .orderBy("id", "desc")
            .queryForLimit(100, 10);
    }
}

特点

  1. 与SQL标准高度相似的API设计,上手快
  2. 专为多重筛选条件设计的clause从句,让你一句话写到底,不用写又臭又长的条件拼接从句
  3. 简单的insertupdate语句,避免了名与值的位置匹配问题
  4. 表字段名与实体类属性名的自动转换/映射

举例说明

结构说明

  1. 继承HentaiDAO,获得CRUD的快捷方法,在DAO类中声明具体的增删改查语句
  2. 实现JDBCBridge接口,执行由DAO类所生成的要求执行的SQL语句

用户表结构

字段名 类型 长度
id bigint --
name varchar 50
type_id bigint --
create_time datetime --
is_delete bit --
balance decimal(10, 2) --

用户类实体

@Table("sys_user")
public class User
{
	@Field(pk = true)
    private Long id;
    @Field
    private String name;
    @Field
    private Long typeId;
    @Field
    private java.util.Date createTime;
    @Field
    private Boolean isDelete;
    @Field
    private java.math.BigDecimal balance;
    
    @Transient
    private String typeName;
    
    // getter/setter methods bellow...
}

测试用User实例

User user = new User();
user.setId(112233L);
user.setName("matrixy");
user.setTypeId(12L);
user.setDelete(true);
user.setBalance(new BigDecimal("3.14"));
user.setCreateTime(new java.util.Date());

编写DAO类,需要继承HentaiDAO

public class UserDAO extends HentaiDAO
{
    
}

编写测试用JDBCBridge

// 这里只是输出生成的SQL,用于跟踪与调试
public class TestBridge implements JDBCBridge
{
    @Override
    public Object insert(String sql, Object... values)
    {
        System.out.println("insert: " + sql);
        return 0;
    }

    @Override
    public long execute(String sql, Object... values)
    {
        System.out.println("execute: " + sql);
        return 0;
    }

    @Override
    public long update(String sql, Object... values)
    {
        System.out.println("update: " + sql);
        return 0;
    }

    @Override
    public <T> T queryOne(String sql, Class type)
    {
        System.out.println("queryOne: " + sql);
        return null;
    }

    @Override
    public <E> List<E> query(String sql, Class type, Object... values)
    {
        System.out.println("query: " + sql);
        return null;
    }

    @Override
    public <T> T queryForValue(String sql, Class type, Object... values)
    {
        System.out.println("queryForValue: " + sql);
        return null;
    }
}

注册JDBCBridge

在应用初始化时,调用HentaiDAO.registerJDBCBridge(new TestBridge())来设置运行时的JDBCBridge。

字段名转换映射

  1. 名称转换,数据库里的字段名一段以下线线_联接,在与Java实体类属性对应时,可通过HentaiDAO.setupFieldNameConverter(new CamelCaseConverter())来设置使用字段名到类成员的转换器(CamelCaseConverter就是由_风格转为驼峰式的内置转换器)。
  2. 类型映射,Java实体类的属性类型必须为装箱后的对象类型,对照关系如下:
数据库类型 Java类型 备注
bigint Long --
tinyint Integer --
Int Integer --
Varchar String --
Datetime java.util.Date --
Bit Boolean 因为各IDE生成的setter与getter方法名不统一,可能会有问题
TEXT String --
Decimal java.math.BigDecimal --

INSERT 插入

执行insertInto().valueWith(user).save()将输出

insert into users (name, type_id, create_time, is_delete, balance)
values (?, ?, ?, ?, ?)
  • insertInto有重载方法,可另行指定表名。
  • valueWith()方法的参数为一个java实体类的实例,HentaiDAO将自动反射出需要持久化的字段名,并且转换为数据库字段名的带下划线的形式,比如userId将转换为user_id的形式。
  • 如果实体类的某个字段不需要保存到数据库中,需要加上@Transient注解。
  • save()方法的返回值为新插入行的id值。

UPDATE 更新

执行update().valueWith(user).by(clause("sex = ?", "男").and("age = ?", 20)).execute();将输出:

update users
set name = "matrixy",
    type_id = ?,
    create_time = ?,
    is_delete = ?,
    balance = ?,
where
    sex = ?
    and age = ?;

执行update().valueWith(user).byId().execute();将输出:

update users
set name = "matrixy",
    type_id = ?,
    create_time = ?,
    is_delete = ?,
    balance = ?,
where id = ?;

使用byId()从句,将自动从实体类中反射得到@Field(pk = true)的成员属性转换后得到的字段名,用于where从句的字段名。

  • skip(String... fields),跳过一个或多个字段,在更新时不更新这些字段(字段名应该是带下划线的数据库字段名)。
  • only(String... fields),只更新参数列表里的这些字段的值(字段名应该是带下划线的数据库字段名)。
  • valueWith(String fieldName, Object fieldValue)手动指定要更新的字段与值(字段名应该是带下划线的数据库字段名)。
  • 另外:update不会更新主键值。
  • 另外,onlyskipvalueWith等方法,都返回了本UpdateSQL实例,也就是说可以一直连续的接下去,比如:
update("sys_user")
    .valueWith("name", "test")
    .valueWith("is_delete", 1)
    .valueWith("create_time", new java.util.Date())
    .by(clause("id = ?", 1))
    .execute();

SELECT 查询

查询的完整形式如下:

    select(String...fields)
        .from(String tableName)
        .where()
        .orderBy()
        .queryForXXX()

对应于SELECT查询的几个基本要求,其中最简形式可以是select(Bean.class).byId(1).queryForXXX(),这将使用实体类成员属性里带有@Field(pk = true)的属性名转转换后作为待查的字段,byId()方法是一个预定义的针对于主键查询的快速方法。

  • select()select(String... fieldNames)方法,用于创建查询语句,如果指定了fieldNames不定长参数时,将使用参数的值来代替configureFields()方法的返回值。另外,fieldNames参数的值应当为数据库字段名格式,不需要转换,HentaiDAO会自动进行转换映射,如果fieldNames值中有as重命名,将不会进行自动重命名。
  • from(String tableName)方法,用于指定待查的表名。或使用from(Bean.class),由类注解的@Table()来获取表名。
  • where()byId()方法,指定查询时的条件,where()方法将在下面的条件从句上详解。byId方法将使用Bean.class类成员属性上设定了@Field(pk = true)的成员属性名称转换后作为字段名,使用=比较。
  • orderBy(String fieldName, String order)orderBy(String fieldName),指定排序的字段名以及升降序,如果未指定order参数,则默认为升序,如果order参数值不为asc(不区分大小写),则为降序。
  • desc()asc(),单独声明降序或升序排序。
  • Long queryForCount()返回查询结果集的行数。
  • EntityClass query()返回单个结果,实例化并自动填充值到指定的类型。
  • List<EntityClass> queryForList()返回全部结果集,实例化并自动填充到指定的类型。
  • List<EntityClass> queryForLimit(int offset, int count),返回结果集的自offset起,共count条结果,实例化并自动填充到指定的类型。

Clause 条件从句

clause()方法是HentaiDAO类中实明的方法,用于创建一个Clause类的实例,提供联合的条件从句,目前只支持and的联合,clause()方法返回的值为自身实例引用,可使用and()无限联接。 条件联接:添加条件从句时,可根据传入值的情况决定是否使条件从句生效,是否联接到SQL语句中去:

  • gtz,只有当值大于0时,此条件从句才生效(greater than zero)。
  • like,只有当值非null非空串非不可见字符串,此条件从句才生效,将自动在值的前后追回上%,并且将从句中的=改为like
  • notnull,只有当值非null非空串非不可见字符串,此条件从句才生效。

举例有如下查询,现在只关心clause方法:

select("id")
    .from("test")
    .where(
        clause("id = ?", 1)
    ).query()

生成的SQL如下:

select id from test where id = 1;
  1. 当使用:clause("id = ?", gtz(1)).and("sex = ?", gtz(0))时,将输出:
-- gtz要求值必须大于0,如果值小于等于0,将忽略掉整个条件从句,所以后一个条件从句将被忽略
select id from test where id = 1;
  1. 当使用:clause("name = ?", like("ha")).and("name like ?", like(""))时,将输出:
-- like要求值必须为非空的可见字符串,所以将忽略后一个条件从句,前一个条件从句将生效,并且将=替换为like
select id from test where name like '%ha%';
  1. 当使用:clause("name = ?", null)时,将输出:
-- null不是以=相比较,所以这里做了适配
select id from test where name is null

HentaiDAO类成员方法列表

  1. static void setupJDBCBridge(JDBCBridge bridge),设置JDBC执行委托
  2. static void setupFieldNameConverter(IFieldNameConverter converter),设置表字段名到类成员名称的转换器,默认是CamelCaseConverter
  3. abstract String[] configureFields(),需要子类实现的,完成表的字段名配置
  4. abstract String configureTableName(),需要子类实现的,完成表名的配置
  5. String primaryKey(),可在子类覆盖实现,完成表的主键名的配置,默认返回值为"id"
  6. UpdateSQL update(),创建UPDATE语句
  7. UdateSQL update(String tableName),创建UPDATE语句
  8. InsertSQL insertInto(),创建INSERT语句
  9. InsertSQL insertInto(String tableName),创建INSERT语句,并且指定表名
  10. QuerySQL select(),创建SELECT语句
  11. `QuerySQL select(String... fields),以指定的字段名,创建SELECT语句
  12. Clause clause(String sql, Object value),以参数化的从句以值,创建条件从句
  13. Clause clause(String sql),以SQL直接创建条件从句
  14. Concatenation gtz(Object data),以指定的值创建gtz语义的条件联接值
  15. Concatenation notnull(Object data),以指定的值创建notnull语义的条件联接值
  16. Concatenation like(Object data),以指定的值创建like语义的条件联接值
  17. List<TypeClass> query(String sql, Class type, Object...values),直接执行查询语句,并且返回结果集
  18. TypeClass queryForValue(String sql, Class type, Object...values),直接执行查询语句,并且返回相应的类型值
  19. TypeClass queryForOne(String sql, Class type, Object...values),直接执行查询语句,并且返回相应的一个结果
  20. long execute(String sql, Object...values),直接执行UPDATE/INSERT语句,并且返回影响的行数
  21. today(),返回当天的字符串表示,比如2018-03-31
  22. tomorrow(),返回当天的后一天的字符串表示,比如2018-04-01
  23. date(int offset),返回以当天为基准,之前或之后第offset天的字符串表示,比如date(-1)将返回前一天的日期字符串。
  24. date(Date date, int offset),返回以指定参数指定的日期为基准,之前或之后第offset天的字符串表示。

TODO

  1. 连接的事务会话测试
  2. JDBCBridge,与其它连接池管理包配合
  3. group by从句

问题

  1. 难以表述过于复杂的SQL语句
  2. 暂时只支持integer类型的自增主键
  3. 目前只在Mysql上使用过,其它数据库未进行适配与测试

空文件

简介

使用全新而又熟悉的方式来快速编写CRUD 展开 收起
Java
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/matrixy/HentaiDAO.git
git@gitee.com:matrixy/HentaiDAO.git
matrixy
HentaiDAO
HentaiDAO
master

搜索帮助