一 环境搭建
- 首先,你必须安装 JDK 1.6,推荐JDK 8u112
- 其次,为了运行 Nutz.Dao,你必须要有一个数据库软件:
- Mysql,Postgresql, SQLServer, Oracle, DB2 , H2都可以。
- 建立一个 Java 项目:
- 推荐使用Eclipse或Idea等IDE工具
- 你要将数据库的 JDBC Driver 和你喜欢的连接池加入项目的 classpath。
- NutDao并不依赖MVC环境及Ioc.
- 在Mvc环境下,通常使用Ioc管理NutDao的实例.
- NutDao是线程安全的,无需重复创建其实例.
建立POJO
创建NutzDao实例,定义dataSource (重点)
二 Dao接口的基本操作
插入 |
Insert |
一条 SQL 插入一条记录或者多条记录 |
插入 |
FastInsert |
一条 SQL ,通过batch插入多条记录 |
删除 |
Delete |
一条 SQL 删除一条记录 |
更新 |
Update |
一条 SQL 更新一条或者多条记录 |
获取 |
Fetch |
一条 SQL 获取一条记录 |
查询 |
Query |
一条 SQL 根据条件获取多条记录 |
清除 |
Clear |
一条 SQL 根据条件删除多条记录 |
建表 |
Create |
根据实体建表 |
删表 |
Drop |
根据实体/表名称进行删表 |
聚合 |
Func |
执行sum,count等操作 |
传统关系型数据库定义了数据库的四种操作,增删改查,但是nutz.dao从用户角度,又扩展了好几种操作,而且都支持条件增删改查,专门为条件封装了接口,但是也有它的局限性
1 不生成外键,也不推荐用外键
2 只能解决一般建表需求,复杂的表结构需通过自定义sql完成
三 注意事项
主键
对于一个 POJO,你可以同时为其声明 @Id 和 @Name,它们都能正常工作。你只需要保证 @Name 对应的字段 在数据库里有唯一性约束即可。 但是通常, Nutz.Dao 并没有假设你同时在一个 POJO 里应用 @Id, @Name 和 @PK,如果你 这么做了,可能会引发一些奇怪的问题。事实上,你也不可能这么做,不是吗?
TIPS:注解 @Id 与注解 @Name 声明的字段不需要另外加上注解 @Column; 在注解 @PK 里面声明的对应复合主键的字段不需要另外加上注解 @Column;
默认的,nutz.dao认为一个整数型的主键是自增的。所以它会在执行
Dao.insert(pet);
之后,为你插入的对象执行
SELECT MAX(id) from t_pet;(如果你使用的数据库如mysql,支持主键返回,那这个操作不会出现)
不同的数据库获得自增值得方式是不一样的,通过@Next注解,声明数据库本地方言,来获取自增值,注意这里的自增是由数据库来实现的,而非nutzDao的内部自增机制
复杂的sql条件
- 对于 Nutz.Dao 来说,它本质上就是将你的 Java 对象转化成 SQL,然后交给 JDBC 去执行。
- 而 SQL 中,当执行数据删除和查询操作时,最常用的就是 WHERE 关键字。
- WHERE 关键字后面的就是所谓的复杂查询条件
有些情况,数据库中的字段同 Java 对象中的字段并不同名, 所以就需要给 Java 字段上的数据库字段注解加上参数 @Column("数据库字段名") 如果你通过 Cnd.wrap() 硬编码某个字段,那么当这个字段数据库字段名发生改变时,你就需要改动很多。 因此你希望仅仅将对于数据库的变动限制在 Java 对象的源文件里 所以 Nutz 提供了 Cnd.where() 方法
提供Criteria接口(继承Condition接口)
- 让程序员更容易的拼装复杂逻辑的条件
- 让生成的 SQL 可以被参数化,更好的支持 PreparedStatement
// 创建一个 Criteria 接口实例
Criteria cri = Cnd.cri();
// 组装条件
if(...){
cri.where().andIn("id", 3,4,5).andIn("name", "Peter", "Wendal", "Juqkai");
}else if(...){
cri.where().andLT("id", 9);
}
if(...){
cri.where().andLike("name", "%A%");
}
cri.getOrderBy().asc("name").desc("id");
// 执行查询
List<MyObj> list = dao.query(MyObj.class, cri, null);
分页
使用数据库的应用程序,多数情况下都需要使用 分页 这个功能。尤其是在 Web 应用程序中,后端的分页查询尤其的普遍。 在以往的使用经验中,一个分页查询,除了能获取到一个列表外,我们通常需要如下几个信息才能在客户端显示出一个完整的翻页条。
- 当前页数 -- 第几页
- 页大小 -- 每页有多少条记录
- 总页数 -- 一共多少页
- 总记录数 -- 如果不分页,一共有多少条记录
当我们获得了这四条信息后,对于维护一个翻页查询就足够。
Nutz.Dao 的查询接口天然就支持分页查询。
<T> List<T> query(Class<T> classOfT, Condition condition, Pager pager);
这个接口有三个参数
- classOfT 告诉 Nutz.Dao 需要查询的实体类型
- condition 告诉 Nutz.Dao 查询出的列表需要符合的条件。详细请看 复杂条件。
- 最后一个参数,就是告诉 Nutz.Dao 将结果如何分页的了。
Pager 对象有如下几个注意事项:
- 如果 pager 被传入了 null,则不分页
- 生成 Pager 对象的时候需要传入 “当前页数” 和 “页大小”
- Pager 虽然有 getRecordCount() 和 getPageCount() 方法,但是它不会自动被设值 -- 因为考虑到效率
- 通过 Pager.setRecordCount() 可以为 Pager 设置结果集的总数,Pager 会通过 getPageCount() 返回总页数
- 分页页数从1开始算,如果页数是0,代表不分页,请特别注意
支持一对一,一对多,多对多映射,支持自定义sql
事务
对于事务安全,nutz提供了事务模板
- org.nutz.trans.Trans 类提供了两个函数 exec
- 一个接受数目可变的 Atom 对象
- 一个接受一个整型值用以界定本事务的级别,以及一个数目可变的 Atom 对象
- Atom 类就是 java.lang.Runnable 的一个别名
- 在一个 Atom 里,无论同时操作多少 DataSource,都是事务安全的(由于不是使用XADataSource,无法100%保证)
- 你可以通过实现自己的 Transaction 实现类,扩展 Nutz.Dao 对于事务的支持
示例
final Pet pet1 = dao.fetch(Pet.class,"XiaoBai");
final Pet pet2 = dao.fetch(Pet.class,"XiaoHei");
pet1.setNickname("BaiBai");
pet2.setNickname("HeiHei");
// Begin transaction
Trans.exec(new Atom(){
public void run() {
dao.update(pet1);
dao.update(pet2);
}
});
提供一个org.nutz.trans.Atom接口的匿名类来实现,在里面的所有的dao操作都是原子性的,以为他们在同一个原子里面“Atom”
设置事务的隔离级别
public static void exec(int level, Atom... atoms);
这里的第一个参数 level 和 java.sql.Connection 接口中的 setTransactionIsolation 规定的 level 是一样的。下面 是在 java.sql.Connection 里面关于 level 参数的 JDoc 说明:
它可以是下列常量中的任意一个值:
- Connection.TRANSACTION_READ_UNCOMMITTED
- Connection.TRANSACTION_READ_COMMITTED
- Connection.TRANSACTION_REPEATABLE_READ
- Connection.TRANSACTION_SERIALIZABLE
实体解析
Class<?> ---> Entity<?> ---> PojoMaker ---> DaoStatement ---> DaoExecutor ---> JDBC
| | | | |
\------------------------ NutDao 的实现流程 -----------------------/
- PojoMaker 接口负责语句的生成
- DaoExecutor 接口负责语句的执行
内置服务类
单独的调用一行接口,多传入一个参数到没什么,但是如果频繁的被使用,每次都要多写一个参数毕竟很是麻烦,nutzdao提供了服务类来简化这些操作
- 如果 POJO 即声明了 @Id 又声明了 @Name,那么适合采用 IdNameEntityService
- 如果 POJO 仅声明了 @Id,那么适合采用 IdEntityService
- 如果 POJO 仅声明了 @Name,那么适合采用 NameEntityService
- 如果 POJO 即没声明了 @Id 又没声明了 @Name,那么适合采用 EntityService
- 这四个内置的服务类,仅仅提供了一些基本的操作。
- 这些服务类都是支持泛型。
- 你可以直接使用,或者你可以从这四个服务类继承你自己的实现。
- 如果你继承这些服务类,请务必声明泛型
Dao拦截器
var ioc = {
dao : {
type : "org.nutz.dao.impl.NutDao",
args : [{refer:"dataSource"}],
fields : {
interceptors : [
"log", //输入sql语句到日志,这是nutdao默认情况下唯一启用的拦截器
"time", // 打印sql时耗
"net.demo.MyDaoInterceptor", // 自定义拦截器,需要实现DaoInterceptor
{refer:"superI"} // 引用另外一个bean作为拦截器
]
}
}
}