在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:dbm开源软件地址:https://gitee.com/pistols/dbm开源软件介绍:dbm基于spring jdbc实现的轻量级orm 项目github地址: dbm 交流群: 604158262 目录
特色
示例项目单独使用dbm的示例项目boot-dbm-sample 要求JDK 1.8+spring 4.0+ maven当前snapshot版本:4.7.4-SNAPSHOT 若使用snapshot版本,请添加snapshotRepository仓储: <repository> <id>oss</id> <url>https://oss.sonatype.org/content/repositories/snapshots/</url> <snapshots> <enabled>true</enabled> </snapshots></repository> 添加依赖: <dependency> <groupId>org.onetwo4j</groupId> <artifactId>onetwo-dbm</artifactId> <version>4.7.4-SNAPSHOT</version></dependency> spring的依赖请自行添加。 一行代码启用在已配置好数据源的前提下,只需要在spring配置类(即有@Configuration注解的类)上加上注解@EnableDbm即可。 @EnableDbm @Configuration public class SpringContextConfig { } 实体映射@Entity @Table(name="TEST_USER_AUTOID") public class UserAutoidEntity { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="ID") protected Long id; @Length(min=1, max=50) protected String userName; @Length(min=0, max=50) @Email protected String email; protected String mobile; protected UserStatus status; //省略getter和setter} 注意这里用到了一些jpa的注解,含义和jpa一致:
java的字段名使用驼峰的命名风格,而数据库使用下划线的风格,dbm会自动做转换
id策略dbm支持jpa的GenerationType的id策略,此外还提供了通过@DbmIdGenerator自定义的策略:
详细使用GenerationType.IDENTITY@Entity@Table(name="t_user")public class UserEntity implements Serializable { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) protected Long id;} GenerationType.TABLE@Entity@Table(name="t_user")public class UserEntity implements Serializable { @Id @GeneratedValue(strategy = GenerationType.TABLE, generator="tableIdGenerator") @TableGenerator(name = "tableIdGenerator", table="gen_ids", pkColumnName="gen_name", valueColumnName="gen_value", pkColumnValue="seq_test_user", allocationSize=50 ) protected Long id;} GenerationType.SEQUENCE@Entity@Table(name="t_user")public class UserEntity implements Serializable { @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seqGenerator") @SequenceGenerator(name="seqGenerator", sequenceName="SEQ_TEST_USER") protected Long id;} DbmIdGenerator比如使用了dbm集成的snowflake策略,下面的配置使用了默认配置的snowflake,如果需要配置不同的datacenter和machine,建议自己实现CustomIdGenerator接口。 @Entity@Table(name="t_user")public class UserEntity implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO, generator="snowflake") @DbmIdGenerator(name="snowflake", generatorClass=SnowflakeGenerator.class) protected Long id;} 复合主键映射jpa支持三种复合主键映射策略,dbm目前只支持一种: @IdClass 映射。映射方法如下:假设有一个表有两个主键:id1,id2。实体的Java代码如下: @Data@Entity@Table(name="composite_table")@IdClass(CompositeId.class)public class CompositeEntity { @Id Long id1; @Id Long id2; @Transient CompositeId id; public CompositeId getId() { return new CompositeId(id1, id2); } public void setId(CompositeId id) { this.id1 = id.getId1(); this.id2= id.getId2(); } //....其它属性 @Data public static class CompositeId implements Serializable { Long id1; Long id2; }} 解释:
复合主键实体的查找方法为: CompositedId cid = new CompositedId(1, 1);CompositeEntity entity = baseEntityManager.load(CompositeEntity.class, cid);int deleteCount = baseEntityManager.removeById(CompositeEntity.class, entity.getId()); 枚举处理枚举映射dbm支持jpa的@Enumerated枚举映射注解,使用方法和jpa一样,默认为EnumType.ORDINAL int值类型映射,可以通过注解属性指定为EnumType.STRING名称映射。 但是,当枚举为EnumType.ORDINAL映射的时候,ordinal的值是从0开始根据定义时的先后顺序决定,这使得我们开发的时候很不方便,比如我有一个枚举类型,是需要映射为int类型,但是值并不是从0开始的,这时候就相当的尴尬,因为你既不能用默认为EnumType.ORDINAL,也不能用EnumType.STRING。 所以dbm还另外增加了自定义的int值映射接口DbmEnumValueMapping,只要枚举类型实现了这个接口,就可以自定义返回实际的映射值,比如: @Entity@Table(name="TEST_USER")public class UserEntity { @Id Long id; @Enumerated(EnumType.ORDINAL) UserGenders gender; public static enum UserGenders { FEMALE("女性"), MALE("男性"); final private String label; private UserGenders(String label) { this.label = label; } public String getLabel() { return label; } }} 如果按照jpa的做法,枚举类型映射为@Enumerated(EnumType.ORDINAL)后,用户实体的gender属性对应的数据库列只能是0(FEMALE)和1(MALE)。在dbm里,你可以通过实现DbmEnumValueMapping接口,返回自定义的映射值,比如10(FEMALE)和11(MALE)。 @Entity@Table(name="TEST_USER")public class UserEntity { @Id Long id; @Enumerated(EnumType.ORDINAL) UserGenders gender; public static enum UserGenders implements DbmEnumValueMapping { FEMALE("女性", 10), MALE("男性", 11); final private String label; final private int value; private UserGenders(String label, int value) { this.label = label; this.value = value; } public String getLabel() { return label; } @Override public int getMappingValue() { return value; } }} 枚举属性查询时的处理
json映射有时候,我们需要在数据库的某个字段里存储json格式的数据,又想在获取到数据后转为java对象使用,这时你可以使用 @DbmJsonField 注解,这个注解会在保存实体的时候把对象转化为json字符串,然后在取出数据的时候自动把字符串转化为对象。示例: class SimpleEntity { @DbmJsonField private ExtInfo extInfo; public static class ExtInfo { String address; List<String> phones; }} 如果该字段是泛型,需要保存类型信息,可以设置storeTyping属性为true class SimpleEntity { @DbmJsonField(storeTyping=true) private Map<String, ConfigData> configData; public static class ExtInfo { String address; List<String> phones; }} 需要添加依赖: <dependency> <groupId>org.onetwo4j</groupId> <artifactId>onetwo-jackson</artifactId> </dependency> 敏感字段映射加解密映射对于一些不适宜明文存储的字段信息,比如api密钥,存储的时候自动加密,获取的时候自动解密,此时可以使用@DbmEncryptField 注解。 @Entity@Table(name="TEST_MERCHANT")public class MerchantEntity implements Serializable { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="ID") protected Long id; @DbmEncryptField protected String apikey;} 在@DbmRepository 使用这个功能时,可以在插入的参数后面加上后缀函数: /***** * @name: batchInsert * 批量插入 */ insert into test_merchant (id, apikey) values (:id, :apikey?encrypt) 注意
脱敏映射对于另一些字段,我们可能并不需要加解密,而只是在存储或者获取的时候,按照一定的规则脱敏。比如手机号码取出的时候自动对后面四位打上星号,或者邮件地址只显示第一个字符和@后面的字符,则可以使用 @DbmSensitiveField 注解进行脱敏映射。 @Entity@Table(name="TEST_USER")public class UserEntity implements Serializable { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="ID") private Long id; private String mobile; @DbmBindValueToField(name="mobile") //查询实体时,此字段的值来自mobile字段 @Transient //此字段无需保存到数据库 @DbmSensitiveField(leftPlainTextSize=7, on=SensitiveOns.SELECT) // 保留手机号码只显示左边7位,如13612345678,取出脱敏后mobile的值为:1361234**** private String mobileUnsensitive; @DbmSensitiveField(leftPlainTextSize=1, sensitiveIndexOf="@", on=SensitiveOns.SELECT) // 邮件地址左边保留一个长度的字符,@后面的字符都保留,其余用星号代替,如[email protected],取出脱敏后为:t***@gmail.com private String email;} 解释 DbmSensitiveField 属性解释如下:
注意 此功能从 4.7.4 版本开始支持 字段绑定@DbmBindValueToField 注解可以帮某个字段的值绑定到另一个字段,绑定后,实体查询时,此字段的值将会取自绑定的值。例子可以参考 脱敏映射 注意 此功能从 4.7.4 版本开始支持 其它特有的映射@DbmField注解@DbmField 注解可自定义一个值转换器,用于从数据库表获取的字段值转换为Java对象的属性值,和把Java对象的属性值转换为数据库表的字段值。 BaseEntityManager接口和QueryDSL大多数数据库操作都可以通过BaseEntityManager接口来完成。 先来个简单的使用例子: @Resource private BaseEntityManager entityManager; @Test public void testSample(){ UserAutoidEntity user = new UserAutoidEntity(); user.setUserName("dbm"); user.setMobile("1333333333"); user.setEmail("[email protected]"); user.setStatus(UserStatus.NORMAL); //save Long userId = entityManager.save(user).getId(); assertThat(userId, notNullValue()); //update String newMobile = "13555555555"; user.setMobile(newMobile); entityManager.update(user); //fetch by id user = entityManager.findById(UserEntity.class, userId); assertThat(user.getMobile(), is(newMobile)); //通过实体属性查找,下面的调用相当于sql条件: where mobile='13555555555' and status IN ('NORMAL', 'DELETE') and age>18 user = entityManager.findOne(UserAutoidEntity.class, "mobile", newMobile, "status:in", Arrays.asList(UserStatus.NORMAL, UserStatus.DELETE), "age:>", 18); assertThat(user.getId(), is(userId)); //下面的调用相当于sql条件: where registerTime>=:date1 and registerTime<:date2 entityManager.findList(UserEntity.class, "registerTime:date in", new Object[]{date1, date2}) } BaseEntityManager对象的find开头的接口,可变参数一般都是按键值对传入,相当于一个Map,键是实体对应的属性(+冒号+操作符,可选,不加默认就是=),值是对应属性的条件值: entityManager.findOne(entityClass, propertyName1, value1, propertyName2, value2......); entityManager.findList(entityClass, propertyName1, value1, propertyName2, value2......); key,value形式的参数最终会被and操作符连接起来。 其中属性名和值都可以传入数组或者List类型的参数,这些多值参数最终会被or操作符连接起来,比如:
entityManager.findList(entityClass, new String[]{propertyName1, propertyName2}, value1, propertyName3, value3); 最终生成的sql语句大概是: select t.* from table t where (t.property_name1=:value1 or t.property_name2=:value1) and t.property_name3=:value3
entityManager.findList(entityClass, propertyName1, new Object[]{value1, value2}, propertyName3, value3); 最终生成的sql语句大概是: select t.* from table t where (t.property_name1=:value1 or t.property_name1=:value2) and t.property_name3=:value3
entityManager.findList(entityClass, propertyName1, new Object[]{value1, value2}, propertyName3, value3, K.IF_NULL, IfNull.Ignore); 那么,当value3(或者任何一个属性对应的值)为nul时,最终生成的sql语句大概是: select t.* from table t where (t.property_name1=:value1 or t.property_name1=:value2) property_name3条件被忽略了。 操作符BaseEntityManager的属性查询支持如下操作符: Query DSL APIdbm还提供了一个专门用于构建查询的dsl api //使用 querys dsl apiUserAutoidEntity queryUser = Querys.from(entityManager, UserAutoidEntity.class) .where() .field("mobile").is(newMobile) .field("status").is(UserStatus.NORMAL) .end() .toQuery() .one();assertThat(queryUser, is(user)); 注意:4.7.3后,query dsl api 已集成到 BaseEntityManager 接口,可以通过 BaseEntityManager 直接创建查询: public Optional<User> findBy(String month, Long userId)
|
请发表评论