Jbomo框架系列教程(三)-ORM 有更新!

  |   0 评论   |   1,982 浏览

第三章:ORM

ORM主要功能也是fork至jfinal1.9版本,在原来的基础上做改进。

简单示例

  1. 配置数据源

除了上述例子中的配置外,添加一组数据源配置

jbomo.devMode = true
jbomo.server.port = 8083
jbomo.server.host = localhost

jbomo.datasource.url =jdbc:mysql://192.168.2.169/jbomo-example?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
jbomo.datasource.user = admin_union
jbomo.datasource.password =gM_v9og51Pn_BRcT2d8R

示例中的建表语句

CREATE TABLE `t_person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(5) DEFAULT NULL,
  `addtime` char(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  1. Person实体类

​ 通常情况下,实体类并不需要任何编码,只需要继承Model通用实体类。注意泛型中要指定具体实体类名。

public class Person extends Model<Person> {
}
  1. PersonService服务类

​ PersonService需要继承通用服务类Service,通用服务类中封装了通用的增、删、改、查以及dao实体属性,如下所示,可以使用dao进行通用方法外的db操作。

public class PersonService extends Service<Person> {
    public List<Person> findByAge(int age) {
        String sql = "select * from " + table.getName() + " where age = ? order by addtime";
        List<Person> persons = dao.find(sql, age);
        return persons;
    }
}
  1. Module配置类

​ 如上述配置类示例,下面配置了 t_person 表与Person实体类的映射关系,没有指定数据源时,默认使用应用缺省数据源,也就是main数据源。

public class Example03Module extends DaoModule {
    @Override
    public void configTable(Tables tables) {
        tables.add("t_person", Person.class);
    }
}
  1. 业务测试类
public class Example03Appliaction {

    public static void main(String[] args) {
        Jbomo.run();
        doPersonTest();
    }
    
    private static void doPersonTest() {
        Person person = new Person();
        person.set("name","李四").set("age",18).set("addtime", DateUtil.getCurDateTimeStr());
        PersonService personService = new PersonService();

        // 保存person对象
        personService.save(person);

        // 根据ID加载Person对象
        Person person1 = personService.findById(1);
        System.out.println(person1.toJson());

        // 根据年龄获取Person列表
        personService.findByAge(18).stream().forEach(p -> {
            System.out.println(p.toJson());
        });
    }
}
{"addtime":"2019-01-18 13:56:12","name":"张三","id":1,"age":18}
{"addtime":"2019-01-18 13:56:12","name":"张三","id":1,"age":18}
{"addtime":"2019-01-18 14:05:54","name":"李四","id":2,"age":18}
{"addtime":"2019-01-18 14:11:04","name":"李四","id":3,"age":18}
{"addtime":"2019-01-18 14:58:57","name":"李四","id":4,"age":18}
  1. 示例代码工程目录图

1547795047866

数据源配置说明

​ Jbomo支持多数据源配置,如下配置所示,没有指定数据源名称的为系统缺省数据源(main)。所以在配置其它非主数据源的时候应该避开“main”数据源名称。

jbomo.datasource.url = ${jbomo.mysql.jdbcUrl}
jbomo.datasource.user = ${jbomo.mysql.user}
jbomo.datasource.password =${jbomo.mysql.password}

jbomo.datasource.sharding.url = ${jbomo.datasource.sharding.url}
jbomo.datasource.sharding.user = ${jbomo.datasource.sharding.user}
jbomo.datasource.sharding.password =${jbomo.datasource.sharding.password}

jbomo.datasource.visitcnt.url = ${jbomo.datasource.visitcnt.url}
jbomo.datasource.visitcnt.user = ${jbomo.datasource.visitcnt.user}
jbomo.datasource.visitcnt.password = ${jbomo.datasource.visitcnt.password}

​ 数据源的配置项说明:

配置项 说明
driverClass 数据库驱动类,默认(“com.mysql.jdbc.Driver”)
maxPoolSize 连接池最大连接数,默认(100)
minPoolSize 连接池最新连接数,默认(10)
initialPoolSize 初始化连接数,默认(10)
factory 连接池实现方式(c3p0,druid,hikari等,暂时只实现c3p0)
partitionEnable 是否需要分库分表
partitionDatasources 分库时候逻辑数据源使用,指定分库物理数据源,多个数据源用逗号“,”隔开

​ 当业务需要对数据进行分库时,数据源还分为逻辑数据源和物理数据源,逻辑数据源只需要配置partitionEnable为ture以及指定几个分库物理数据源partitionDatasources。如下示例:

jbomo.datasource.pes.partitionEnable=true
jbomo.datasource.pes.partitionDatasources=p1,p2,p3

jbomo.datasource.p1.url = ${jbomo.datasource.p1.url}
jbomo.datasource.p1.user = ${jbomo.datasource.p1.user}
jbomo.datasource.p1.password = ${jbomo.datasource.p1.password}
jbomo.datasource.p1.partitionEnable = true     

jbomo.datasource.p2.url = ${jbomo.datasource.p1.url}
jbomo.datasource.p2.user = ${jbomo.datasource.p1.user}
jbomo.datasource.p2.password = ${jbomo.datasource.p1.password}
jbomo.datasource.p2.partitionEnable = true  

jbomo.datasource.p3.url = ${jbomo.datasource.p1.url}
jbomo.datasource.p3.user = ${jbomo.datasource.p1.user}
jbomo.datasource.p3.password = ${jbomo.datasource.p1.password}
jbomo.datasource.p3.partitionEnable = true     

dao&Model

​ Model封装了众多操作数据库的通用方法,适用于单节点的小项目快速开发使用。为了系统微服务化以及代码结构更清晰,Jbomo框架封装了通用服务类Service,包括通用增、删、改、查以及dao实体属性。

dao是Service示例中的一个Model的实例化对象,这边的dao不能当做一个model实体进行save或者delete操作。

​ Service示例:

public class PersonService extends Service<Person> {

    public List<Person> findByAge(int age) {
        String sql = "select * from " + table.getName() + " where age = ? order by addtime";
        List<Person> persons = dao.find(sql, age);
        return persons;
    }

}

​ 注意Service必须指定泛型中具体Model类名。

​ Model的其它用法如下:


        // 删除值为2的Person
        dao.deleteById(2);

        // 加载id为3的Person对象
        Person person = dao.findById(3);

        // 获取person的名称
        String name = person.getStr("name");

        // 获取person的年龄
        int age = person.getInt("age");

        // 更新person,建议这样使用
        update(person.set("age",20));
        // 不建议这样使用,因为该使用方式不适应于rpc远程服务调用
        person.set("age",21).update();

        // 分页查询
        dao.paginate(1,10,"select * "," from "+table.getName());

        // 关联查询示例
        String sql =  "select b.*, u.user_name from blog b inner join user u on b.user_id=u.id where b.id=?";
        Blog blog = dao.findFirst(sql, 123); 
        String name = blog.getStr("user_name"); 

Model注意事项

1.model.set()与model.put()

​ model.set()会根据model的表字段校验是否包含该属性,如果model映射的表不存在该属性字段会抛出ActiveRecordException异常。

​ model.put()不会校验是否存在该属性,仅当做hashmap键值对存储。

2.model实体复制

	model.setAttrs(model2);

​ 当实体数据存储在一个hashmap中的时候,可以使用如下方式拷贝属性:

	   //可以使用setAttrs拷贝,当不存在字段时候会抛异常
	   model.setAttrs(hashMap);
	   //可以使用hasColumnLabel判断是否存在字段
	   hashMap.forEach((k,v)->{
            if (model.getTable().hasColumnLabel(k)){
                model.set(k,v);
            }
        });

Db + Record模式

​ Db 类及其配套的 Record 类,提供了在 Model 类之外更为丰富的数据库操作功能。使用Db 与Record 类时,无需对数据库表进行映射,Record 相当于一个通用的 Model。以下为Db + Record 模式的一些常见用法:

// 创建name属性为James,age属性为25的record对象并添加到数据库 
Record user = new Record().set("name", "James").set("age", 25); 
Db.save("user", user); 
 
// 删除id值为25的user表中的记录 
Db.deleteById("user", 25); 
 
// 查询id值为25的Record将其name属性改为James并更新到数据库 
user = Db.findById("user", 25).set("name", "James"); 
Db.update("user", user); 
 
// 查询id值为25的user, 且仅仅取name与age两个字段的值 
user = Db.findById("user", 25, "name, age"); 
 
// 获取user的name属性 
String userName = user.getStr("name"); 
 
// 获取user的age属性 
Integer userAge = user.getInt("age"); 
 
// 查询所有年龄大于18岁的user 
List<Record> users = Db.find("select * from user where age > 18"); 
 
// 分页查询年龄大于18的user,当前页号为1,每页10个user 
Page<Record>  userPage  = Db.paginate(1, 10,  "select *",  "from user where age > ?", 18); 

事务处理

以下为事务处理示例:

boolean succeed = Db.tx(new IAtom(){ 
  public boolean run() throws SQLException { 
    int  count = Db.update("update account set cash = cash  -  ? where id = ?", 100, 123); 
    int  count2 = Db.update("update account set cash = cash + ? where id = ?", 100, 456); 
    return count == 1 && count2 == 1; 
  }}); 

​ 以上两次数据库更新操作在一个事务中执行,如果执行过程中发生异常或者 invoke()方法返回 false,则自动回滚事务。

评论

发表评论

validate