sorms - 简易 ORM 框架


Apache 2.0
跨平台
Java

软件简介

简易ORM框架

  • 此框架主要为在使用Spring框架的以下用户考虑:

    • 喜欢JPA注解,但讨厌hibernate和spring data jpa效率低下的.同时又不想失去sql灵活性的.

    • 喜欢Mybatis的直接,但对mybatis的易用性和可维护性提出质疑的.

  • 此框架在hibernate和mybatis做了折中,并且执行性能超过两者.

  • 此框架主要基于ef-orm框架理念

  • 使用jpa注解,但不完全实现jpa规范,单表增,删,改比较方便,同时对级联也做了支持,但不实现延迟加载功能,必须手动调用,才能加载级联对象(此处主要降低jpa实现复杂度).

  • jpa支持注解如下: @Column,@Table,@Entity,@Id,@OneToOne,@OneToMany,@ManyToMany,@ManyToOne.@JoinColumn,@JoinTable,@Version

  • 使用了代码增强技术,增强了实体类.需要继承DBObject类.并使用配置实现代码增强.继承DBObject类的java bean 只要调用set方法即可精确修改数据库对象.

  • 支持级联配置

  • 支持Map格式的数据对象返回.

  • 支持使用模板写sql,主要使用jetbrick-template实现.

  • 支持对象操作的乐观锁功能.

  • 支持实体对象生成功能

  • 不支持一级,二级缓存(Spring cache已经足够好)

  • 整合支持querydsl,jooq用法,提高系统可维护性.能降低80%~90%的sql硬编码.极大提高系统的可维护性.

  • 支持mybatis的resultMap,但无需编写xml,只需使用@Column注解和数据库字段映射即可,对于一条sql语句对应一个主类带子类对象,使用@OneToOne注解标记即可实现主类、子类的组装.

  • 此框架为整合性框架,感谢ef-orm,jfinal,BeetlSQL,Nutz,mybatis,jetbrick-orm

快速预览

  1. spring 环境下

    @Bean
    public OrmConfig getOrmConfig(DaoTemplate dt) {
    OrmConfig config = new OrmConfig();
    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(DataSource ds) {
        DaoTemplate dt = new DaoTemplate(ds);
        return dt;
    }
    
  2. 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.DBCascadeField;
import sf.database.DBField;
import sf.database.annotations.Comment;
import sf.database.annotations.FetchDBField;
import sf.database.annotations.Type;
import sf.database.jdbc.extension.ObjectJsonMapping;
import sf.database.DBObject;

import javax.persistence.*;
import java.math.BigDecimal;
import java.util.*;

@Entity
@Table(name = "wp_users")
@Comment("用户表")
public class User extends 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 DBField {
      id, loginName, password, nicename, email, url, registered, activationKey, status, displayName,maps, spam, deleted,weight;
    }

    /**
     * 级联字段
     */
    public enum CascadeField implements DBCascadeField {
        roles, userMetaSet
    }

    public User() {

    }
    ... get set方法
}

在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 list = dt.selectList(User.class, sql);

  • 执行模板sql

    tag loadSql(“queryUserByName”)

    [[

    select * from wp_users
        #tag where()

    #if(id)
            and id=${p(id)}
            #end

    #if(username)
            and login_name=${p(username)}
            #end

    #if(nicename)
            and nicename=${p(nicename)}
            #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 q = QueryDSLTables.relationalPathBase(User.class);
    SQLQuery query = new SQLQuery();
    query.select(q).from(q).where(q.string(User.Field.displayName).isNotNull())
            .orderBy(new OrderSpecifier<>(Order.ASC, q.column(User.Field.id)));
    Page page = dt.sqlQueryPage(query, 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.jooqSelectOne(query);