同步操作将从 Show/sorm 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
sorms是一个全功能orm工具, 同时具有Hibernate与Mybatis的优点。该框架主要适合使用Spring,Spring boot用户
<!-- 引入jar包 -->
<dependency>
<groupId>com.github.atshow</groupId>
<artifactId>sorm</artifactId>
<version>1.0.10</version>
</dependency>
配置maven插件
<plugin>
<groupId>com.github.atshow</groupId>
<artifactId>sorm</artifactId>
<version>1.0.10</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();
}
#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.*;
@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中引入
@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);
String sql = "select * from wp_users";
List<User> list = dt.selectList(User.class, 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);
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);
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,User.class);
普通
##2018-12-15 16:17:51 更新
引用大牛的话:Mybatis最大的问题不在于开发效率,而在维护效率上。其过于原生的数据库操作方式,难以避免项目维护过程中的巨大成本。 当数据库字段变化带来的修改工作虽然可以集中到少数几个XML文件中,但是依然会分散在文件的各处,并且你无法依靠Java编译器帮助你发现这些修改是否有错漏。 在一个复杂的使用Mybatis的项目中,变更数据库结构往往带来大量的CodeReview和测试工作,否则难以保证项目的稳定性。
为了实现实体类的动态更新,数据实体类需要继承: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的生效
在上面的例子中,还可以看到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>
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方法
}
// 创建一个数据源
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());
dao.insert(user);//使用该方法插入后,主键值将自动被写入user对象中.
//批量插入
List<User> modelList = new ArrayList<>();
....
dao.batchInsert(modelList);
除上面的用法,也提供了快速单一插入和快速批量插入的方法(快速插入都不返回主键)
dao.insertFast(user);
//批量插入
List<User> modelList = new ArrayList<>();
....
dao.batchInsertFast(modelList);
//更新对象,如果有查询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);
//删除对象.如果有查询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);
//具体可以查看api注释.
<T extends DBObject> int updateAndSet(T obj);
<T extends DBObject> int updateWithVersion(T obj);
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(OrmIterator<T> ormIt, T query);
/**
* 查询限制条数和起始位置的迭代结果.回调形式.
* @param ormIt 迭代回调方法
* @param query 查询
* @param start 起始数
* @param limit 限制数
* @param <T> 泛型
*/
//查询限制条数和起始位置的迭代结果.回调形式.
<T extends DBObject> void selectIterator(OrmIterator<T> ormIt, T query, int start, int limit);
//stream lambda形式迭代结果.
<T extends DBObject> void selectStream(OrmStream<T> ormStream, T query);
//此注解说明,需要抓取的级联对象的字段.主要是适用于,无需全部查询级联对象字段的值
@FetchDBField
级联对象插入 未提供单独的级联对象插入功能,可以使用普通的对象插入方法,保存级联对象.
级联对象修改 级联对象修改,需要在主对象完整的情况下.使用:
/**
* 将对象插入数据库同时,也将指定级联字段的所有关联字段关联的对象统统插入相应的数据库
* <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);
/**
* 将对象删除的同时,也将指定级联字段的所有关联字段关联的对象统统删除 <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);
/**
* 查找对象列表,并查询级联字段
* @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);
此大类方法主要是为了兼容普通jdbc操作,使与JdbcTemplate使用一致.
自由设置返回值,此功能主要是改进mybatis中的resultMap书写不方便的问题. 对于实体类,当实体类的字段与sql语句返回的字段不一致时,可以使用@Column注解的name值,设置对应的返回字段. 具体请查看DBMethod类中的方法.
支持查询对象拆分到更多的子对象中. 此功能只需要在实体类中,添加一对一的映射,使用@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类型参数传入:
#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);
模板支持跨数据库
dbContext.setSqlTemplateIdUseDialect(true);//打开开关,该开关优先级高于@SqlResource
dt.selectListTemplate(User.class, "queryUserByName", params)// 对于mysql数据库框架会查找模板id为 mysql.queryUserByName 的模板内容
模板指令
id=#p(id)
#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
#if(nicenames)
and nicename #in(nicenames)
#end
not in 可以使用组合方式实现
#if(nicenames)
and nicename not #in(nicenames)
#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
#pageIgnore("order by id")
#pageIgnoreTag()
order by id
#end
#sql("user_cols")
id,login_name,nicename
#end
#sql("queryUserByName")
select #use("user_cols") from wp_users
#use("user_condition")
#end
整合QueryDSL和JOOQ主要是为了给提供类型安全的查询语句生成,避免代码里出现过多的硬编码sql语句,导致维护噩梦. 使用QueryDSL和JOOQ主要以使用固定表为主.
//此处主要是通过QueryDSLTables获取Q类,QueryDSLTables提供缓存功能.
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.queryDSLSelectPage(query,User.class, 2, 3);
//此处主要是通过JooqTables获取Q类,JooqTables提供缓存功能.
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,User.class);
Spring主要使用DaoTemplate类,此类已与Spring jdbc做了集成.
//多数据源配置
@Bean
public OrmConfig getOrmConfig(@Autowired(required = false) @Qualifier("xaMysql") DataSource xaMysql,
@Autowired(required = false) @Qualifier("sqlite") DataSource sqlite,
@Autowired(required = false) @Qualifier("postgresql") DataSource postgresql,
@Autowired(required = false) @Qualifier("oracle") DataSource oracle,
@Autowired(required = false) @Qualifier("sqlserver") DataSource sqlserver) {
SimpleRoutingDataSource routing = new SimpleRoutingDataSource();
routing.getDataSources().put("mysql", sqlite);
routing.getDataSources().put("sqlite", sqlite);
// routing.addDataSource("postgresql", postgresql);
routing.setDefaultKey("mysql");
DaoTemplate dt = new DaoTemplate(routing);
// DaoTemplate dt = new DaoTemplate(xaMysql);
OrmConfig config = OrmConfig.getInstance();
config.setDbClient(dt);
//需要扫描的实体类.此处提供自动建表功能.
config.setPackagesToScan(StringUtils.split("db.domain", ","));
config.setUseTail(true);
config.setBeanValueType(OrmValueUtils.BeanValueType.fast);
config.setUseSystemPrint(false);
config.init();
return config;
}
@Bean(name = "daoTemplate")
public DaoTemplate geDaoTemplate(OrmConfig config) {
return (DaoTemplate) config.getDbClient();
}
smallorm.packages=db.domain #指定扫描若干包,如果有多个请使用,分隔
smallorm.show-sql=true #sql日志开关
smallorm.bean-value-type=method #使用哪一种bean转换,method(默认),field,reflectasm
smallorm.use-tail=false #是否使用tail获取额外属性.
smallorm.allow-drop-column=false #扫描到实体后,如果准备修改表,如果数据库中的列多余,是否允许删除列
smallorm.create-table=true #扫描到实体后,如果数据库中不存在,是否建表
smallorm.alter-table=true #扫扫描到实体后,如果数据库中存在对应表,是否修改表
smallorm.batch-size=100 #批处理数量
smallorm.enhance-scan-packages=true #对配置了包扫描的路径进行增强检查,方便单元测试
smallorm.open-stream-iterator=false #是否开启流式迭代
smallorm.sql-template-path=classpath*:sql/**/*.sql #sql模板位置
smallorm.sql-template-debug=false #是否开启sql模板调试模式
smallorm.sql-template-type=enjoy #使用的sql模板类型(默认)
框架支持类似mybatis的mapper功能. DBClient 提供了所有需要知道的API,但通过sqlid来访问sql有时候还是很麻烦,sorm支持Mapper,将sql文件映射到一个interface接口。接口的方法名与sql文件的sqlId一一对应。 接口必须实现DaoMapper接口,它提供了内置的CRUD方法,如insert,update,merge,delete,unique,selectTemplate,executeTemplate,updateById等 DaoMapper 具备数据库常见的操作,接口只需要定义额外的方法与sqlId同名即可。
@OrmMapper
public interface UserDAOMapper extends DaoMapper<User> {
@ExecuteTemplate(id = "db.user.selectUserByTemplateId")
List<User> selectAllTemplateId(@OrmParam("id") int id);
}
如上select将会对应如下sql文件
#sql("db.user.selectUserByTemplateId")
select * from wp_users where id=#p(id)
#end
使用JDK8编译,可以不必为参数提供名称,框架能自动对应。但必须保证java编译的时候开启-parameters选项。如果未开启编译参数,则可以使用@OrmParam注解()
@ExecuteTemplate
List<User> selectUserByTemplateId(@OrmParam("id") int id);
sorm的mapper方法会根据调用方法名字,返回值,以及参数映射到DBClient相应的查询接口,比如返回类型是List,意味着发起DBClient.selectTemplate 查询,如果返回是一个Map或者Pojo,则发起一次selectOneTemplate查询,如果返回定义为List,则表示查询实体,如果定义为List ,则对应的查询结果映射为Long
定义好接口后,可以通过DBClient.getMapper 来获取一个Dao真正的实现
UserDAOMapper dao = dbClient.getMapper(UserDAOMapper.class);
如果你使用Spring或者SpringBoot,可以参考Spring集成一章,了解如何自动注入Mapper
Mapper 对应的sql文件默认根据配置文件名来确定,可以通过@SqlResource 注解来指定Mapper的id前缀。比如
@OrmMapper
@SqlResource("db.user")
public interface UserCoreDao extends DaoMapper<User> {
@ExecuteTemplate
List<User> select(String name);
}
@OrmMapper
@SqlResource("db.userConsole")
public interface UserConsoleDao extends DaoMapper<User> {
@ExecuteTemplate
List<User> select(String name);
}
这样,这俩个mapper分别访问db.user.select 和 db.userConsole.select
7.1. 内置CRUD DaoMapper接口包含了内置的常用查询,
public interface DaoMapper<T extends DBObject> {
......
int merge(T entity);
int insert(T entity);
int update(T entity);
int delete(T entity);
......
}
7.2 sql语句 7.2.1 查询 @ExecuteSQL 执行原生sql语句查询,必须在方法上有@ExecuteSQL注解.
@ExecuteSQL(value = {"select * from wp_users"})
List<User> selectAll();
分页查询需要使用RowLimit限制对象查询个数
@ExecuteSQL(value = {"select * from wp_users"})
Page<User> selectSqlPage(RowLimit rl);
方法参数需要与"?" 一一对应 对于实体类中没有对应属性的值,可以创建Map 打上@Tail注解,将额外的属性写入Map中.
@Tail
private Map<String,Object> map;
7.2.2 执行插入 对返回的主键需要使用 @SelectKey 该主键主要处理返回值的类型 以下是执行插入语句
@ExecuteSQL(value = {"insert into wp_users(login_name,activation_key) values(?,?)"})
@SelectKey(keyColumn = "id", resultType = long.class)
long insertUser(String loginName, String activeKey);
7.2.3 更新,删除和插入类似,唯一的区别是无返回值.
7.4 sql模板 @ExecuteTemplate 主要提供根据模板id执行模板语句以及直接执行模板语句.
@ExecuteTemplate(value = {"select * from wp_users where id =#p(id)"})
User selectSqlOneTemplate(@OrmParam("id") int id);
插入的返回值
@ExecuteTemplate(value = {"insert into wp_users(login_name,activation_key) values(#p(loginName),#p(activeKey))"}, type = DMLType.INSERT)
@SelectKey(keyColumn = "id", resultType = Map.class)
Map insertUserTemplate(@OrmParam("loginName") String loginName, @OrmParam("activeKey") String activeKey);
7.5 自动生成sql语句 @AutoSQL 标识该方法能自动生成sql, 使用该功能必须引入spring-data-commons依赖,框架使用spring-data-commons生成sql语句
@AutoSQL
List<User> findDistinctUserByIdOrderByLoginNameDesc(@Param("id") int id);
此处的@Param为spring-data-commons中的注解.
7.6 额外功能 如果觉得以上注解过于麻烦,还有一种用法,可以直接继承DaoMapper接口,然后再实现该扩展接口即可.
public interface UserDAO extends DaoMapper<User> {
}
@Repository
public class UserDAOImpl extends DaoMapperImpl<User> implements UserDAO {
public UserDAOImpl(@Autowired DBClient dbClient) {
super(User.class, dbClient);
}
}
@Column(name = "maps1", length = 1500)
@Type(ObjectJacksonMapping.class)//使用jackson
private Map<String, String> maps1;
@Column(name = "maps1", length = 1500)
@Type(ObjectFastJsonMapping.class)//使用fastjson
private Map<String, String> maps1;
@Column(name = "maps2")
@Type(javaType = String.class, sqlType = Types.CLOB)
@Convert(converter = ObjectJsonConverter.class)//使用jpa的转换类
private Map<String, String> maps2;
1.1 @MapKey 该注解用于将级联的子对象集合转换为Map类型,可以设置子对象的哪个字段作为key.默认使用主键.
@OrderBy
@OneToMany(targetEntity = UserMeta.class)
@JoinColumn(name = "id", referencedColumnName = "userId")
@MapKeyClass(Integer.class)
@MapKey
private Map<Integer,UserMeta> metaMap = new HashMap<>();
1.2 @SqlResultSetMapping,SqlResultSetMappings 此两注解用于注册sql语句的返回结果,和JAP用法相同.主要用于以下方法:
//根据@SqlResultSetMapping设置返回值,返回的为单个对象,或数组对象
List<?> selectList(String resultSetMapping, String sql, Object... parameters);
//根据@SqlResultSetMapping设置返回值,返回的为单个对象,或数组对象
List<?> selectList(String resultSetMapping, long start, int limit, String sql, Object... parameters);
//根据@SqlResultSetMapping设置返回值,返回的为单个对象,或数组对象
Object selectOne(String resultSetMapping, String sql, Object... parameters);
注意:如果返回是多个对象,返回值为Object[] 数组,顺序是@SqlResultSetMapping定义的@EntityResult,@ConstructorResult.
2. 多数据源,DBClient中使用如下方法,即可切换数据源.
/**
* 执行sql上下文,比如切换数据源
* @param dataSource 数据源名称
* @return DBClient
*/
DBClient useContext(String dataSource);
/**
* 根据表名生成对应的pojo类
* @param pkg 包名,如 com.test
* @param srcPath: 文件保存路径
* @param config 配置生成的风格
*/
void genPojoCodes(String pkg, String srcPath, GenConfig config);
配置完成数据源后,执行以下方法:
GenConfig genConfig = new GenConfig();
dbClient.genPojoCodes("target", System.getProperty("user.dir") + File.separator + "com/test/abc", genConfig);
SimpleRoutingDataSource routing = new SimpleRoutingDataSource("sqlite",sqlite,null);
DaoTemplate dt = new DaoTemplate(routing);
对于多数据源,请创建多个DaoTemplate实例即可.
User u = new User();
u.setId(23);
u.useQuery().createCriteria().eq(User.Field.id, 1);
dt.update(u);
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。