ORM
配置
在使用数据库之前,需要给Jboot应用做一些配置,实际上,在任何需要用到数据库的应用中,都需要给应用程序做一些配置,让应用程序知道去哪里读取数据。
由于Jboot的数据库读取是依赖于JFinal,所以实际上只要是JFinal支持的数据库类型,Jboot都会支持,比如常用的数据库类型有:
- Mysql
- Oracle
- SqlServer
- postgresql
- sqlite
- 其他标准的数据库
在Jboot应用连接数据库之前,我们需要在resources目录下创建一个jboot.properties配置文件,并在jboot.properties编写内容如下:
jboot.datasource.type=mysql
jboot.datasource.url=jdbc:mysql://127.0.0.1:3306/jbootdemo
jboot.datasource.user=root
jboot.datasource.password=your_password
其中:
- jboot.datasource.type 是配置数据库类型
- jboot.datasource.url 是数据库请求URL地址
- jboot.datasource.user 是数据库需要的账号
- jboot.datasource.password 是数据库需要的密码
高级配置
除了 type
,url
,user
,password
四个配置以外,jbootdatasource 还支持以下配置:
- jboot.datasource.name 数据源的名称
- jboot.datasource.driverClassName 驱动类名
- jboot.datasource.connectionInitSql 连接初始化Sql
- jboot.datasource.poolName 线程池名称
- jboot.datasource.cachePrepStmt 缓存启用
- jboot.datasource.prepStmtCacheSize 缓存大小
- jboot.datasource.prepStmtCacheSqlLimit 缓存限制
- jboot.datasource.maximumPoolSize 线程池大小
- jboot.datasource.sqlTemplatePath sql文件路径
- jboot.datasource.sqlTemplate sql文件,多个用英文逗号隔开
- jboot.datasource.table 该数据源对应的表名,多个表用英文逗号隔开
更多的具体使用,特别是name、table等在分库分表章节会讲到。
Model
model是MVC设计模式中的M,但同时每个model也会对应一个数据库表,它充当 MVC 模式中的 Model 部分。以下是Model 定义示例代码:
public class User extends JbootModel<User> {
public static final User dao = new User().dao();
}
以上代码中的 User 通过继承 Model,便立即拥有的众多方便的操作数据库的方法。在 User中声明的 dao 静态对象是为了方便查询操作而定义的,该对象并不是必须的。同时,model无需定义 getter、setter 方法,无需 XML 配置,极大降低了代码量。
以下是model常见的用法:
// 创建name属性为James,age属性为25的User对象并添加到数据库
new User().set("name", "James").set("age", 25).save();
// 删除id值为25的User
User.dao.deleteById(25);
// 查询id值为25的User将其name属性改为James并更新到数据库
User.dao.findById(25).set("name", "James").update();
// 查询id值为25的user, 且仅仅取name与age两个字段的值
User user = User.dao.findByIdLoadColumns(25, "name, age");
// 获取user的name属性
String userName = user.getStr("name");
// 获取user的age属性
Integer userAge = user.getInt("age");
// 查询所有年龄大于18岁的user
List<User> users = User.dao.find("select * from user where age>18");
// 分页查询年龄大于18的user,当前页号为1,每页10个user
Page<User> userPage = User.dao.paginate(1, 10, "select *", "from user
where age > ?", 18);
注意:User 中定义的 public static final User dao 对象是全局共享的,只能 用于数据库查询,不能 用于数据承载对象。数据承载需要使用 new User().set(…)来实现。
@Table注解
@Table注解是给Model使用的,表示让Model映射到哪个数据库表,使用代码如下:
@Table(tableName = "user", primaryKey = "id")
public class User extends JbootModel <Company> {
}
值得注意的是:
在Jboot应用中,我们几乎感受不到@Table这个注解的存在,因为这部分完全是代码生成器生成的,关于代码生成器,请查看 代码生成器章节。
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);
// 获取user的name属性
String userName = user.getStr("name");
// 获取user的age属性
Integer userAge = user.getInt("age");
// 查询所有年龄大于18岁的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;
}
});
以上两次数据库更新操作在一个事务中执行,如果执行过程中发生异常或者 run()方法返回 false,则自动回滚事务。
更多
请参考JFinal的文档:http://download.jfinal.com/download/3.2/jfinal-3.2-manual.pdf
多数据源
在Jboot中,使用多数据源非常简单。
在以上章节里,我们知道,要连接数据库需要做如下配置:
jboot.datasource.type=mysql
jboot.datasource.url=jdbc:mysql://127.0.0.1:3306/jbootdemo
jboot.datasource.user=root
jboot.datasource.password=your_password
假设我们再增加两个数据源,只需要在jboot.properties文件在添加如下配置即可:
jboot.datasource.a1.type=mysql
jboot.datasource.a1.turl=jdbc:mysql://127.0.0.1:3306/jboot1
jboot.datasource.a1.tuser=root
jboot.datasource.a1.tpassword=your_password
jboot.datasource.a2.type=mysql
jboot.datasource.a2.turl=jdbc:mysql://127.0.0.1:3306/jboot2
jboot.datasource.a2.tuser=root
jboot.datasource.a2.tpassword=your_password
这表示,我们又增加了数据源a1
和数据源a2
,在使用的时候,我们只需要做一下使用:
Company company = new Company();
company.setCid("1");
company.setName("name");
company.use("a1").save();
company.use("a1").save();
表示使用数据源a1
进行保存。
值得注意的是:
在多数据源应用中,很多时候,我们一个Model只有对应一个数据源,而不是一个Model对应多个数据源。假设Company只有在a1
数据源中存在,在其他数据源并不存在,我们需要把a1
数据源的配置修改如下:
jboot.datasource.a1.type=mysql
jboot.datasource.a1.url=jdbc:mysql://127.0.0.1:3306/jboot1
jboot.datasource.a1.user=root
jboot.datasource.a1.password=your_password
jboot.datasource.a1.table=company
jboot.datasource.a2.type=mysql
jboot.datasource.a2.url=jdbc:mysql://127.0.0.1:3306/jboot2
jboot.datasource.a2.user=root
jboot.datasource.a2.password=your_password
jboot.datasource.a1.table=user,xxx(其他非company表)
这样,company在a1
数据源中存在,Jboot在初始化的时候,并不会去检查company在其他数据源中是否存在,同时,代码操作company的时候,不再需要use,代码如下:
Company company = new Company();
company.setCid("1");
company.setName("name");
//company.use("a1").save();
company.save();
代码中不再需要 use("a1")
指定数据源,因为company只有一个数据源。
分库和分表
在Jboot中,分表是通过sharding-jdbc( 网址:https://github.com/shardingjdbc/sharding-jdbc) 来实现的,所以,在了解Jboot的分表之前,请先阅读了解sharding-jdbc的配置信息。
分库分表相关demo: 点击这里
分库
分库意味你有多个数据库,每个数据库会对应一个数据源。
例如,我们的应用有三个数据库,分别是 db1,db2,db3,那么需要我们在 jboot.properties 配置文件里配置上三个数据,配置如下:
jboot.datasource.db1.url = jdbc:mysql://127.0.0.1:3306/db1
jboot.datasource.db1.user = root
jboot.datasource.db1.password =
jboot.datasource.db2.url = jdbc:mysql://127.0.0.1:3306/db2
jboot.datasource.db2.user = root
jboot.datasource.db2.password =
jboot.datasource.db3.url = jdbc:mysql://127.0.0.1:3306/db3
jboot.datasource.db3.user = root
jboot.datasource.db3.password =
我们希望在分库的时候,通过Model的主键ID进行hashcode进行取模,决定分库。因此需要编写分库策略,代码如下:
public class UserDatabaseShardingStrategyConfig implements ShardingStrategyConfiguration {
@Override
public ShardingStrategy build() {
return shardingStrategy;
}
private ShardingStrategy shardingStrategy = new ShardingStrategy() {
@Override
public Collection<String> getShardingColumns() {
//根据id进行分库
return Sets.newHashSet("id");
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, Collection<ShardingValue> shardingValues) {
ListShardingValue shardingValue = (ListShardingValue) shardingValues.stream().findFirst().get();
String dbName = "db" + Math.abs(shardingValue.getValues().iterator().next().toString().hashCode()) % 3;
System.out.println("插入数据到库:" + dbName);
//返回通过计算得到的表
return Sets.newHashSet(dbName);
}
};
}
编写好分库策略后,需要给Model配置上分库策略:
@Table(tableName = "tb_user",
primaryKey = "id",
// 具体的表tb_user${0..2} 表示有三张表 tb_user0,tb_user1,tb_user2,
// main 是默认数据源的名称
actualDataNodes = "main.tb_user${0..2}",
//分表策略
databaseShardingStrategyConfig = UserDatabaseShardingStrategyConfig.class
)
public class UserModel extends JbootModel<UserModel> {
//geter setter
}
分表
demos
例如:有一个userModel,我们希望能进行分为三张表,通过id的hashcode进行取模,代码如下:
@Table(tableName = "tb_user",
primaryKey = "id",
// 具体的表tb_user${0..2} 表示有三张表 tb_user0,tb_user1,tb_user2,
// main 是默认数据源的名称
actualDataNodes = "main.tb_user${0..2}",
//分表策略
tableShardingStrategyConfig = UserTableShardingStrategyConfig.class
)
public class UserModel extends JbootModel<UserModel> {
//geter setter
}
编写UserModel的分表策略 UserTableShardingStrategyConfig,代码如下:
public class UserTableShardingStrategyConfig implements ShardingStrategyConfiguration {
@Override
public ShardingStrategy build() {
return shardingStrategy;
}
private ShardingStrategy shardingStrategy = new ShardingStrategy() {
@Override
public Collection<String> getShardingColumns() {
//根据id进行分表
return Sets.newHashSet("id");
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, Collection<ShardingValue> shardingValues) {
ListShardingValue shardingValue = (ListShardingValue) shardingValues.stream().findFirst().get();
String tableName = "tb_user" + Math.abs(shardingValue.getValues().iterator().next().toString().hashCode()) % 3;
System.out.println("插入数据到表:" + tableName);
//返回通过计算得到的表
return Sets.newHashSet(tableName);
}
};
}
编写配置文件:
jboot.datasource.type=mysql
jboot.datasource.url=jdbc:mysql://127.0.0.1:3306/jbootsharding
jboot.datasource.user=root
jboot.datasource.password=
jboot.datasource.shardingEnable=true
进行UserModel保存到数据库
@RequestMapping("/sharding")
public class ShardingController extends JbootController {
public void index() {
UserModel user = new UserModel();
user.setId(StringUtils.uuid());
user.setName("Michael yang");
user.save();
renderText("插入数据成功,请查看数据库...");
}
public static void main(String[] args) {
Jboot.run(args);
}
}
具体demo请参考:
https://gitee.com/fuhai/jboot/tree/master/src/test/java/sharding