• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

sorm: java small orm,使用jpa注解,不完全实现jpa规范-----最好用的orm框架之一 ...

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

sorm

开源软件地址:

https://gitee.com/parken/SormGit

开源软件介绍:

Small ORM

sorms是一个全功能orm工具, 同时具有Hibernate与Mybatis的优点。该框架主要适合使用Spring,Spring boot的用户

主要功能特点介绍

  • 开发效率
    • 全面拥抱JPA注解,并通过对注解的扩展和JPA实体类的增强,能极其方便的完成单表增删改查功能.
    • 数据模型支持Pojo,Map/List
    • 支持自动建表功能.创建完成JPA实体类,运行即可创建数据库表
    • 支持级联功能,但不实现延迟加载功能(需要通过手动调用,才能加载级联对象,此处主要是为了降低jpa级联实现的复杂度).
    • 支持Map格式的数据对象返回(框架不区分字段大小写,要求数据库设计对字段大小写不敏感).
    • 支持乐观锁功能.
    • 支持SQL查询转换为实体对象功能
    • 支持类似mybatis的resultMap,但无需编写xml映射,实体类只需使用@Column注解和sql返回字段一一对应即可.
    • 支持实体类中的类似mybatis Example Criteria查询,对于简单的CRUD操作,无需手写SQL.
    • 集成支持querydsl,jooq用法,能降低80%~90%的sql硬编码.极大提高系统的可维护性.
    • SQL模板功能主要基于enjoy实现,更容易编写和调试,以及额外的扩展.
    • 可以针对单个表(或者视图)代码生成pojo类
  • 维护性
    • 使用类型安全的查询,当修改数据库表字段时,可以通过编译提示方便修改类字段.避免mybatis修改数据库字段带来的调试风险.
    • 无缓存功能,避免hibernate,mybatis带来的缓存一致性问题.
    • SQL以enjoy模板管理,支持自定义文件位置,方便程序开发和数据库SQL调试。
    • 可以自动将sql文件映射为dao接口类
  • 其他
    • 框架基于JPA实体类加枚举字段的理念开发而成.
    • JPA注解必须写在字段上,不支持写在方法上.
    • 支持的JPA注解如下:@Column,@Table,@Entity,@Id,@OneToOne,@OneToMany,@ManyToMany,@ManyToOne.@JoinColumn,@JoinTable,@Version,@MapKey,@SqlResultSetMapping,SqlResultSetMappings
    • 使用了代码增强技术,增强了实体类.能精确修改数据库对象(需要继承DBObject类.并使用插件实现代码增强.继承DBObject类的java bean 只要调用普通的set方法即可).
    • 支持主从数据库配置,并支持分库分表的中间件如sharding-jdbc和mycat
    • 性能远超Hibernate,MyBatis
    • 支持跨数据库平台,开发者所需工作减少到最小,目前跨数据库支持mysql,postgres,oracle,sqlserver,sqlite.
    • 支持ClickHouse,主要支持基本的表创建,插入,修改和更新,删除;支持以原生SQL方式查询.
    • 支持脱离Spring环境独立运行.
    • 主要基于jdbc实现,框架极其轻量.几乎全部功能都采用单例模式实现.
    • 部分功能参考:ef-orm,jfinal,BeetlSQL,Nutz,mybatis,jetbrick-orm 在此表示一并感谢.
    • 最低要求jdk8,兼容jdk11.源码请使用jdk8编译

快速预览

  1. spring 环境下引入maven
<!-- 引入jar包 --><dependency>    <groupId>com.github.atshow</groupId>    <artifactId>sorm</artifactId>    <version>最新版本</version></dependency>

配置maven插件

<plugin>    <groupId>com.github.atshow</groupId>    <artifactId>sorm</artifactId>    <version>最新版本</version>    <executions>        <execution>            <goals>                <goal>enhanceJavassist</goal>            </goals>        </execution>    </executions></plugin>
    @Bean	public OrmConfig getOrmConfig(DataSource dataSource) {	    DaoTemplate dt = new DaoTemplate(dataSource);		OrmConfig config = new OrmConfig();		config.setDbClient(dt);		config.setPackagesToScan(StringUtils.split("db.domain",","));		config.setDbClient(dt);		config.setUseTail(true);		config.setFastBeanMethod(false);		config.init();		return config;	}		@Bean(name="daoTemplate")	public DaoTemplate geDaoTemplate(OrmConfig config) {            return (DaoTemplate) config.getDbClient();    }
  1. spring boot配置application.properties中配置
#jpa实体类所在的包smallorm.packages=db.domain...

spring boot的main方法中加入增强代码的方法调用

public static void main(String[] args) throws Exception {        //jpa实体类所在的包		new EntityEnhancerJavassist().enhance("db.domain");		SpringApplication.run(SefApplication.class, args);	}

引入spring-boot-jdbc-starter

3.编写jpa实体类

package db.domain;import sf.database.annotations.Comment;import sf.database.annotations.FetchDBField;import sf.database.annotations.Type;import sf.database.jdbc.extension.ObjectJsonMapping;import javax.persistence.*;import java.math.BigDecimal;import java.util.*;import lombok.Data;@Data@Entity@Table(name = "wp_users")@Comment("用户表")public class User extends sf.core.DBObject {    private static final long serialVersionUID = 1L;    @Id    @GeneratedValue(strategy = GenerationType.AUTO)    private Long id;    @Column(name = "login_name", length = 60, nullable = false)    private String loginName;// 登陆名    @Column(length = 64)    private String password;    @Column(length = 50)    private String nicename;    @Column(length = 100)    private String email;    @Column(length = 100)    private String url;    @Column    @Temporal(TemporalType.TIMESTAMP)    private Date registered;    /**     * 激活码     */    @Column(name = "activation_key", length = 60, nullable = false)    private String activationKey;    @Column    private int status;    @Column(name = "display_name", length = 250)    @Enumerated(EnumType.STRING)    private Names displayName;    @Column    private Boolean spam;    @Column    private boolean deleted;    @Column(precision = 10,scale = 5)    private BigDecimal weight;    @Transient    private boolean lock;    @Column(name = "maps",length = 1500)    @Type(ObjectJsonMapping.class)    private Map<String,String> maps;    @ManyToMany    @Transient    @OrderBy("id asc,role desc")    @JoinTable(name = "user_role", joinColumns = {            @JoinColumn(name = "user_id", referencedColumnName = "id")}, inverseJoinColumns = {            @JoinColumn(name = "role_id", referencedColumnName = "id")})    private List<Role> roles;    @OrderBy    @Transient    @FetchDBField({"id","key"})    @OneToMany(targetEntity = UserMeta.class)    @JoinColumn(name = "id", referencedColumnName = "userId")    private Set<UserMeta> userMetaSet = new LinkedHashSet<UserMeta>();    public enum Names {        zhangshang, lisi    }    /**     * 普通字段     */    public enum Field implements sf.core.DBField {      id, loginName, password, nicename, email, url, registered, activationKey, status, displayName,maps, spam, deleted,weight;    }    /**     * 级联字段     */    public enum CascadeField implements sf.core.DBCascadeField {        roles, userMetaSet    }}

在dao中引入

    @Resource    private DaoTemplate dt;

以daoTemplate操作sql方法.

  • 插入对象
User user = dt.selectOne(new User());User u = new User();u.setLoginName(UUID.randomUUID().toString());u.setDeleted(false);u.setCreated(new Date());u.setActivationKey("23k4j2k3j4i234j23j4");//插入对象,生成的语句为:insert into wp_users(activation_key,created,deleted,login_name) values(?,?,?,?)int i = dt.insert(u);
  • 执行原生sql
String sql = "select * from wp_users";List<User> list = dt.selectList(User.class, sql);
  • 执行模板sql
#sql("queryUserByName")select * from wp_users    #where()         #if(id)         and id=#p(id)         #end         #if(username)         and login_name=#p(username)         #end         #if(nicename)         and nicename=#p(nicename)         #end                  #if(nicenames)         and nicename #in(nicenames)         #end    #end#end

java代码

Map<String, Object> query = new HashMap<>();query.put("id", 1);List<User> list2 = dt.selectListTemplate(User.class, "queryUserByName", query);
  • 执行Querydsl
SQLRelationalPath<User> q = QueryDSLTables.relationalPathBase(User.class);SQLQuery<User> query = new SQLQuery<User>();query.select(q).from(q).where(q.string(User.Field.displayName).isNotNull())        .orderBy(new OrderSpecifier<>(Order.ASC, q.column(User.Field.id)));Page<User> page = dt.sqlQueryPage(query,User.class, 2, 3);
  • 执行jooq代码
JooqTable<?> quser = JooqTables.getTable(User.class);JooqTable<?> qrole = JooqTables.getTable(Role.class);Select<?> query = DSL.select(quser.fields()).from(quser, qrole).where(quser.column(User.Field.id).eq(1));User u = dt.getJooq().jooqSelectOne(query,User.class);

性能测试图

测试性能测试图

##2018-12-15 16:17:51 更新

  • 1.支持对数据库关键字无需使用标识符.

一、概述

框架诞生初衷:Hibernate和Mybatis各走极端,在笔者实际使用中,Hibernate和Mybatis带来了极大的维护问题,导致大家有很多无意义的加班.

Mybatis的问题

引用大牛的话:Mybatis最大的问题不在于开发效率,而在维护效率上。其过于原生的数据库操作方式,难以避免项目维护过程中的巨大成本。当数据库字段变化带来的修改工作虽然可以集中到少数几个XML文件中,但是依然会分散在文件的各处,并且你无法依靠Java编译器帮助你发现这些修改是否有错漏。在一个复杂的使用Mybatis的项目中,变更数据库结构往往带来大量的CodeReview和测试工作,否则难以保证项目的稳定性。

  • 1、关联表多时,字段多的时候,sql工作量很大。
  • 2、sql依赖于数据库,导致数据库移植性差。
  • 3、由于xml里标签id必须唯一,导致DAO中方法不支持方法重载。
  • 4、对象关系映射标签和字段映射标签仅仅是对映射关系的描述,具体实现仍然依赖于sql。
  • 5、DAO层过于简单,对象组装的工作量较大。
  • 6、不支持级联更新、级联删除。
  • 7、Mybatis的日志除了基本记录功能外,其它功能薄弱很多。
  • 8、编写动态sql时,不方便调试,尤其逻辑复杂时。
  • 9、提供的写动态sql的xml标签功能简单,编写动态sql仍然受限,且可读性低。

参考:https://zhuanlan.zhihu.com/p/45044649

Hibernate的问题

  • 概念复杂
  • 性能不佳
  • 使用优化困难.
  • 过度设计

额外说明

  1. 在JPA实体类注解基础上,增加了枚举字段,用于表示具体的数据库字段和级联字段.
  2. 使用了静态代码增强技术.做到了真正的实体类值有变化才执行DML(增,删,改)操作
  3. 为了兼容各数据库,对Map类型的返回,不区分字段大小写,此处要求数据库设计对字段大小写不敏感
  4. 为了最大程度支持数据库查询的灵活性,所有的返回值由你决定(实体类,Java基本类型,String,Map,List,Object[]等类型).
  5. 数据库支持:支持Sqlserver2005及以上版本,Oracle8,MySQL5,PostgreSQL9,SQLite3 数据库.

二、实体操作

实体类继承

为了实现实体类的动态更新,数据实体类需要继承:sf.core.DBObject

public class XXX extends sf.core.DBObject 

DBObject类做了特殊设计:在json序列化时,不会序列化不相关的属性.对于的数据字段需要实现继承:sf.core.DBField接口的枚举

public enum Field implements sf.core.DBField{    XXX}

具体可以参考快速开发中的User类以及sorm-test工程.此处是为解析表结构做准备,对于数据字段的枚举描述,可以看到后面的Example查询,以及querydsl,jooq集成依赖这些字段.

实体类创建

使用标准的JPA注解,框架中添加了额外的几个注解,用于补充JPA的表创建
@Comment 用来定义数据库中的字段和表的注释。
@SavedDefaultValue 插入未设置值时使用对象属性的默认值(比如默认的初始化的值).
@FetchDBField 级联需要抓取的字段,只对级联关系生效
@SmallEntity 用于描述一个实体的行为
@SmallResults 结果集描述,主要用于SQL结果集映射到对象中的子对象.
@Tail 将未匹配的字段塞入map中.必须是Map类型上才能使用该注解,主要用于对象返回
@Type 扩展数据类型的注解,可用于支持新的数据映射方式
@UniqueKeyGenerator 唯一键生成策略,只对标注@Id的生效
@ColumnDefine 定义字段类型,如无符号整形
@CreatedDate 插入时自动设置当前时间
@LastModifiedDate 插入时自动设置当前时间和修改时自动设置当前时间

实体类增强.

在上面的例子中,还可以看到spring boot中的代码增强:

new EntityEnhancerJavassist().enhance("db.domain");

该代码主要是使用javassit对继承了DBObject的实体类做了静态代码增强.代码增强主要是对各个数据库字段的set方法做了增强,如下代码:

@Column(length = 64)private String password;...public void setPassword(String password) {   this.password = password;}

增强后代码变为:

public void setPassword(String password) {    if (this._recordUpdate) {//此处可实现当对象有set值后,即可更新或插入对应的值(无论是否为空).        this.prepareUpdate(User.Field.password, password);    }   this.password = password;}

同时也提供基于ASM的实现使用maven构建时,可以配置Maven-Plugin,使其在编译完后自动扫描编译路径并执行增强操作。请使用:

 <plugin>    <groupId>com.github.atshow</groupId>    <artifactId>sorm</artifactId>    <version>最新版本号</version>    <executions>        <execution>            <goals>                <goal>enhanceASM</goal>            </goals>        </execution>    </executions></plugin>

单表操作

编写jpa实体类

package db.domain;import sf.database.annotations.Comment;import sf.database.annotations.FetchDBField;import sf.database.annotations.Type;import sf.database.jdbc.extension.ObjectJsonMapping;import javax.persistence.*;import java.math.BigDecimal;import java.util.*;@Entity@Table(name = "wp_users")@Comment("用户表")public class User extends sf.core.DBObject {    private static final long serialVersionUID = 1L;    @Id    @GeneratedValue(strategy = GenerationType.AUTO)    private Long id;    @Column(name = "login_name", length = 60, nullable = false)    private String loginName;// 登陆名    @Column(length = 64)    private String password;    @Column(length = 50)    private String nicename;    @Column(length = 100)    private String email;    @Column(length = 100)    private String url;    @Column    @Temporal(TemporalType.TIMESTAMP)    private Date registered;    /**     * 激活码     */    @Column(name = "activation_key", length = 60, nullable = false)    private String activationKey;    @Column    private int status;    @Column(name = "display_name", length = 250)    @Enumerated(EnumType.STRING)    private Names displayName;    @Column    private Boolean spam;    @Column    private boolean deleted;    @Column(precision = 10,scale = 5)    private BigDecimal weight;    @Transient    private boolean lock;    @Column(name = "maps",length = 1500)    @Type(ObjectJsonMapping.class)    private Map<String,String> maps;    @ManyToMany    @Transient    @OrderBy("id asc,role desc")    @JoinTable(name = "user_role", joinColumns = {            @JoinColumn(name = "user_id", referencedColumnName = "id")}, inverseJoinColumns = {            @JoinColumn(name = "role_id", referencedColumnName = "id")})    private List<Role> roles;    @OrderBy    @Transient    @FetchDBField({"id","key"})    @OneToMany(targetEntity = UserMeta.class)    @JoinColumn(name = "id", referencedColumnName = "userId")    private Set<UserMeta> userMetaSet = new LinkedHashSet<UserMeta>();    public enum Names {        zhangshang, lisi    }    /**     * 普通字段     */    public enum Field implements sf.core.DBField {      id, loginName, password, nicename, email, url, registered, activationKey, status, displayName,maps, spam, deleted,weight;    }    /**     * 级联字段     */    public enum CascadeField implements sf.core.DBCascadeField {        roles, userMetaSet    }    public User() {    }    ... 省略get set方法}

创建Dao操作类

// 创建一个数据源SimpleDataSource dataSource = new SimpleDataSource();dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1/nutzdemo");dataSource.setUsername("root");dataSource.setPassword("root");
// 创建一个DBClient实例,在真实项目中, DBClient通常由Spring托管, 使用注入的方式获得.DBClient dao = new DBClient(dataSource);
// 创建表dao.createTable(User.class);//如果存在该表则不创建.
User user = new User();user.setLoginName("ABC");user.setNicename("CDF");dao.insert(user);System.out.println(p.getId());
  1. 插入和批量插入对应DBClient中的方法为
dao.insert(user);//使用该方法插入后,主键值将自动被写入user对象中.//批量插入List<User> modelList = new ArrayList<>();....dao.batchInsert(modelList);

除上面的用法,也提供了快速单一插入和快速批量插入的方法(快速插入都不返回主键)

dao.insertFast(user);//批量插入List<User> modelList = new ArrayList<>();....dao.batchInsertFast(modelList);
  1. 修改和批量修改
//更新对象,如果有查询sql,则按查询sql更新对象(优先级高);如果有主键则按主键查询(优先级低).User u = new User();u.setId(1L);u.setNicename("asdfds");u.useQuery().createCriteria().eq(User.Field.id,1).and().eq(User.Field.displayName,"222");dao.update(u);//批量更新,只支持按主键更新,所以必须设置主键,且所有的需要更新的对象中的属性必须一致.使用//第一个对象中的属性,生成批量更新的执行sql.List<User> modelList = new ArrayList<>();....dao.batchUpdate(modelList);
  1. 删除和批量删除
//删除对象.如果有查询sql,则按查询sql删除对象(优先级高);如果无查询sql,将根据设置的属性,生成删除的sql,使用时请注意.User u = new User();u.setId(1L);u.setNicename("asdfds");dao.delete(u);

或者

User u = new User();u.useQuery().createCriteria().eq(User.Field.id,1).and().eq(User.Field.displayName,"222");dao.delete(u);
//批量对象,将根据设置的属性生成删除sql语句,且所有的需要删除的对象中的属性必须一致.使用//第一个对象中的属性,生成批量删除的执行sql.List<User> modelList = new ArrayList<>();....dao.batchDelete(modelList);
  1. 乐观锁当实体对象中,有字段使用JAP注解:@Version标注时,将为该字段启用乐观锁控制.
    支持:整数型,日期类型和字符串类型(字符串类型使用UUID实现)的乐观锁功能.
    默认的insert,update方法已经提供了乐观锁功能.另外,也提供了其他操作乐观锁的功能.
//具体可以查看api注释.<T extends DBObject> int updateAndSet(T obj);<T extends DBObject> int updateWithVersion(T obj);
  1. 查询针对model的查询,只需要在实体类中,设置过值即可.
    也支持使用Example查询
user.useQuery().createCriteria().eq(User.Field.id, 1).and().eq(User.Field.displayName, "222");

如果使用Example查询,将忽略实体类中设值的查询(按主键查询除外).此查询对更新和删除同样有效.更详细的方法注释可以查看DBMethod类.

//根据主键查询<T extends DBObject> T selectByPrimaryKeys(Class<T> clz, Object... keyParams);//查询总数<T extends DBObject> long selectCount(T query);//查询一条记录,如果结果不唯一则抛出异常<T extends DBObject> T selectOne(T query);//使用select ... for update 查询数据<T extends DBObject> T selectOneForUpdate(T query);/** * 查询列表 * @param query 查询请求。 *              <ul> *              <li>如果设置了Query条件,按query条件查询。 否则——</li> *              <li>如果设置了主键值,按主键查询,否则——</li> *              <li>按所有设置过值的字段作为条件查询。</li> *              </ul> * @return 结果 */<T extends DBObject> List<T> selectList(T query);/** * 使用select ... for update 查询数据 * @param query 查询 * @param <T>   泛型 * @return 实体 *///使用select ... for update 查询数据<T extends DBObject> List<T> selectListForUpdate(T query);/** * 查询并分页 * @param query 查询请求 * @param start 起始记录,offset。从0开始。 * @param limit 限制记录条数。如每页10条传入10。 * @return 分页对象 */<T extends DBObject> Page<T> selectPage(T query, int start, int limit);//查询迭代结果.回调形式.<T extends DBObject> void selectIterator(Consumer<Iterable<T>> ormIt, T query);/** * 查询限制条数和起始位置的迭代结果.回调形式. * @param ormIt 迭代回调方法 * @param query 查询 * @param start 起始数 * @param limit 限制数 * @param <T>   泛型 *///查询限制条数和起始位置的迭代结果.回调形式.<T extends DBObject> void selectIterator(Consumer<Iterable<T>> ormIt, T query, int start, int limit);//stream lambda形式迭代结果.<T extends DBObject> void selectStream(Consumer<Stream<T>> ormStream, T query);

级联操作

  1. 级联关系配置使用jpa注解,级联配置基本上和hibernate一样,唯一的区别在于,级联字段注解配置都需要使用Java字段名称,而不是数据库列名.注意:框架对级联处理无延迟加载功能.在jpa注解之外,还添加了额外的几个注解.
//此注解说明,需要抓取的级联对象的字段.主要是适用于,无需全部查询级联对象字段的值@FetchDBField
  1. 级联对象插入未提供单独的级联对象插入功能,可以使用普通的对象插入方法,保存级联对象.

  2. 级联对象修改级联对象修改,需要在主对象完整的情况下.使用:

/** * 将对象插入数据库同时,也将指定级联字段的所有关联字段关联的对象统统插入相应的数据库 * <p> * 关于关联字段更多信息,请参看 '@One' | '@Many' | '@ManyMany' 更多的描述 * @param obj * @param fields 指定字段,控制力度更细,至少一个或多个 描述了什么样的关联字段将被关注。如果为 null,则表示全部的关联字段都会被插入 * @return */int insertCascade(DBObject obj, DBCascadeField... fields);/** * 仅将对象所有的关联字段插入到数据库中,并不包括对象本身 * @param obj    数据对象 * @param fields 字段名称,描述了什么样的关联字段将被关注。如果为 null,则表示全部的关联字段都会被插入 * @return 数据对象本身 * @see javax.persistence.OneToOne * @see javax.persistence.ManyToMany * @see javax.persistence.OneToMany */<T extends DBObject> T insertLinks(T obj, DBCascadeField... fields);/** * 将对象的一个或者多个,多对多的关联信息,插入数据表 * @param obj    对象 * @param fields 正则表达式,描述了那种多对多关联字段将被执行该操作 * @return 对象自身 * @see javax.persistence.ManyToMany */<T extends DBObject> T insertRelation(T obj, DBCascadeField... fields);
  1. 级联对象删除
/** * 将对象删除的同时,也将指定级联字段的所有关联字段关联的对象统统删除 <b style=color:red>注意:</b> * <p> * Java 对象的字段会被保留,这里的删除,将只会删除数据库中的记录 * <p> * 关于关联字段更多信息,请参看 '@One' | '@Many' | '@ManyMany' 更多的描述 * @param obj    对象 * @param fields 指定字段,控制力度更细,至少一个或多个 描述了什么样的关联字段将被关注。如果为 null,则表示全部的关联字段都会被删除 * @param <T>    泛型 * @return 执行结果 */<T extends DBObject> int deleteCascade(T obj, DBCascadeField... fields);/** * 仅删除对象所有的关联字段,并不包括对象本身。 <b style=color:red>注意:</b> * <p> * Java 对象的字段会被保留,这里的删除,将只会删除数据库中的记录 * <p> * 关于关联字段更多信息,请参看 '@One' | '@Many' | '@ManyMany' 更多的描述 * @param obj    数据对象 * @param fields 字段名称,描述了什么样的关联字段将被关注。如果为 null,则表示全部的关联字段都会被删除 * @return 被影响的记录行数 * @see javax.persistence.OneToOne * @see javax.persistence.ManyToOne * @see javax.persistence.ManyToMany */<T extends DBObject> int deleteLinks(T obj, DBCascadeField... fields);/** * 多对多关联是通过一个中间表将两条数据表记录关联起来。 * <p> * 而这个中间表可能还有其他的字段,比如描述关联的权重等 * <p> * 这个操作可以让你一次删除某一个对象中多个多对多关联的数据 * @param obj * @param fields 字段名称,描述了那种多对多关联字段将被执行该操作 * @return 共有多少条数据被更新 * @see javax.persistence.ManyToMany */<T extends DBObject> int deleteRelation(T obj, DBCascadeField... fields);
  1. 级联对象查询
/** * 查找对象列表,并查询级联字段 * @param query  查询 * @param clz    实体类 * @param fields 级联字段 * @param <T>    泛型 * @return 列表 */<T extends DBObject> List<T> fetchCascade(T query, Class<T> clz, DBCascadeField... fields);/** * 查询对象,并返回所有的级联字段的值 * @param obj 实体 * @return 返回带级联字段值得对象 */<T extends DBObject> T fetchLinks(T obj);/** * 查询单一对象 * @param obj    实体类 * @param fields 级联字段 * @return 对象 */<T extends DBObject> T fetchLinks(T obj, DBCascadeField... fields);

Example 查询

该查询和Mybatis-generator中的Example类似,主要是参考tk.mybatis.mapper 实现.简单使用

User user=new User();user.useQuery().createCriteria().eq(User.Field.id, 1).and().eq(User.Field.displayName, "222");List<User> list = dt.selectList(user);

Example支持查询,修改,删除功能.注意:为了提高Example的灵活性,Example中添加了and(),or(),leftP(),rightP() 分别对应:and,or,左括号,右括号等.

三、sql操作

此大类方法主要是为了兼容普通jdbc操作,使与JdbcTemplate使用一致.

  1. 自由设置返回值,此功能主要是改进mybatis中的resultMap书写不方便的问题.对于实体类,当实体类的字段与sql语句返回的字段不一致时,可以使用@Column注解的name值,设置对应的返回字段.具体请查看DBMethod类中的方法.

  2. 支持查询对象拆分到更多的子对象中.此功能只需要在实体类中,添加一对一的映射,使用@SmallResults注解.@Tail 是否将未匹配的字段塞入map中.必须是Map类型上才能使用该注解

//此注解实现:主要解决子对象的创建问题.@SmallResults({    @FieldResult(name = "metaResult.userId", column = "id"/*对应别名*/),    @FieldResult(name = "metaResult.icon", column = "icon"/*对应别名*/)})public class UserResult {    private Long id;    @Column(name = "login_name")    private String loginName;// 登陆名    private String password;    private String nicename;    private MetaResult metaResult;    @Tail    private Map<String,Object> map;    .....  省略get set 
public class MetaResult {    private Long userId;    private String icon;    ..... 省略get set

四、模板操作

模板主要使用enjoy模板实现,基本功能和jfinal中的enjoy sql模板一致,框架只支持Map类型参数传入.文档地址: https://jfinal.com/doc
enjoy 支持 单行注释:### XXXX
多行注释: #-- XXX --#
SQL语句支持/..../,-- 注释符号,建议尽量使用多行注释.

#sql("user_cols")   id,login_name,nicename#end#sql("user_condition")   #where()         #if(id)         and id=#p(id)         #end         #if(username)         and login_name=#p(username)         #end         #if(nicename)         and nicename=#p(nicename)         #end         #if(nicenames)         and nicename #in(nicenames)         #end    #end#end#sql("queryUserByName")select #use("user_cols") from wp_users    #use("user_condition")#end//java调用Map<String, Object> params = new HashMap<>();params.put("id", 1);List<Object> nicenames = Arrays.asList("1", "aa");params.put("nicenames", nicenames);List<User> list = dt.selectListTemplate(User.class, "queryUserByName", params);

模板支持跨数据库

#sql("queryUserByName.mysql")   ...#end// 对于mysql数据库框架会查找模板id为 mysql.queryUserByName 的模板内容,如果未找到,则会使用默认的queryUserByName//支持:oracle, sqlserver, db2, derby, postgresql, mysql, mariadb, hsqldb, access, gbase, sqlite, mongo, h2, cubrid, firebird// 注意都为小写.dt.selectListTemplate(User.class, "queryUserByName", params)

模板指令

  1. p和para:此二处指令主要标识需要作参数替换.p和para等效
id=#p(id) 
  1. where
    结束需要带#end
#where()     #if(id)     and id=#p(id)     #end     #if(username)     and login_name=#p(username)     #end     #if(nicename)     and nicename=#p(nicename)     #end     #if(nicenames)     and nicename #in(nicenames)     #end#end
  1. inin中的变量值为Collection类型
#if(nicenames)and nicename #in(nicenames)#end

not in 可以使用组合方式实现

#if(nicenames)and nicename  not #in(nicenames)#end
  1. pagepage,pageTag;pageIgnore,pageIgnoreTag主要为分页服务.page和pageTag区别:#page为函数调用,#pageTag需要使用#end标签如 #page("a.name,a.id,b.name role_name") ;如果列名较多,可以使用pageTag,如:#pageTag() a.name,a.id,b.name role_name #end
#sql("queryUserByNamePage")select #page("*") from wp_users    #where()         #if(id)         and id=#p(id)         #end         #if(username)         and login_name=#p(username)         #end         #if(nicename)         and nicename=#p(nicename)         #end    #end    #pageIgnoreTag()    order by id    #end#end
  1. pageIgnore标签函数 pageIgnore和pageIgnoreTag,用在翻页查询里,当查询用作统计总数的时候,会忽略标签体内容;二者区别和page和pageTag相同
#pageIgnore("order by id")
#pageIgnoreTag()    order by id#end
  1. useuse主要用于复用sql片段.
#sql("user_cols")   id,login_name,nicename#end#sql("queryUserByName")select #use("user_cols") from wp_users    #use("user_condition")#end
  1. namespacenamespace 指令为 sql 语句指定命名空间,配合 @SqlResource 可以在模板mapper中定义命名空间
#namespace("db.user")    #sql("selectUserByTemplateId")        select * from wp_users where id=#p(id)    #end#end

五、整合QueryDSL,jOOQ,mybatis-dynmic-sql

整合QueryDSL和JOOQ主要是为了提供类型安全的查询语句的生成,避免代码里出现过多的硬编码sql语句,导致维护噩梦.框架主要以使用固定表为主.

  1. QueryDSL地址:http://www.querydsl.com/ ( https://github.com/querydsl/querydsl )
<dependency>    <groupId>com.querydsl</groupId>    <artifactId>querydsl-sql</artifactId></dependency>

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap