前言
这章的内容的确不少,所以这次仍然没有翻译完。需要快速上手的话你最好看看原文档。
-------------------------------------------------------------------------------------
2.7 表和Schema创建
有几个ORMLite提供的工具,可以帮助你为存入数据库的类创建表和schema。
2.7.1 TableUtils类
TableUtils类提供了一些静态方法用以辅助创建和删除表,同样也提供了schema申明。(下面例举出静态方法名,详细说明参见官网)
静态方法原型 |
createTable(ConnectionSource, Class) |
createTableIfNotExists(ConnectionSource, Class) |
createTable(ConnectionSource, DatabaseTableConfig) |
createTableIfNotExists(ConnectionSource, DatabaseTableConfig) |
dropTable(ConnectionSource, Class, boolean ignoreErrors) |
dropTable(ConnectionSource, DatabaseTableConfig, boolean ignoreErrors) |
getCreateTableStatements(ConnectionSource, Class) |
getCreateTableStatements(ConnectionSource, DatabaseTableConfig) |
clearTable(ConnectionSource, Class) |
clearTable(ConnectionSource, DatabaseTableConfig) |
2.7.2 TableCreator类
TableCreator这个类虽然是为使用Spring框架设计的,但是在其他的配置方面是很有用的。它配置ConnectionSource和被程序使用的DAO列表。
如果系统属性ormlite.auto.create.tables设置成true值,他会自动创建和这些DAO相关的表。如果系统属性ormlite.auto.drop.tables设置成true值,它也会自动删除创建的表。这在测试的时候特别有用:你开始使用取得最新schema的测试数据库,但是实际生产过程中你需要手动改变一个具体的schame。你可以在你运行测试脚本的时候设置系统属性,但是在运行实际脚本时要关闭它。
List<Dao<?, ?>> daoList = new ArrayList<Dao<?, ?>>(); daoList.add(accountDao); ... TableCreator creator = new TableCreator(connectionSource, daoList); // create the tables if the right system property is set creator.maybeCreateTables(); ... // later, we may want to drop the tables that were created creator.maybeDropTables();
2.8 唯一标识符字段
数据库中的记录通过定义为唯一的特殊字段成为唯一标识。记录不是必须有唯一标识字段当时很多DAO操作(更新、删除、刷新)都需要一个唯一标识字段。这个标识要么用户提供要么数据库自动生成。标识字段有表中唯一的值并且如果你用DAO根据id查询、删除、刷新或者更新指定行的时候他们必须存在。为了配置一个成员变量作为标识成员,你应该使用下面三个设置之一(而且必须使用一个):@DatabaseField: id, generatedId, generatedIdSequence 。
2.8.1 成员变量使用id
用我们的Account类的示例,字符串name变量被标记有id = true 。这意味着name变量是这个对象的标识字段。每个account存入数据库都必须有一个唯一的name变量值,比如你不能有两行的name都是“John Smith”。
public class Account { @DatabaseField(id = true) private String name; ... }
当你使用DAO利用具体的name值查询时,你将使用标识成员定位数据库中
的Account对象。
Account account = accountDao.queryForId("John Smith"); if (account == null) { // the name "John Smith" does not match any rows }
注意:如果你需要改变对象id字段的值,那么你必须使用Dao.updateId()方法,它获得当前对象的id旧值和新值。
2.8.2 成员变量使用generatedId
你可以配置一个long或integer的变量作为生成的标识字段。每条记录的id号都是数据库自动生成的。
public class Order { @DatabaseField(generatedId = true) private int id; ... }
传递一个Order对象去创建和存储到数据库时,数据库返回一个生成的id值并且ORMLite设置给对象。在大部分数据库类型中向表中插入一条新记录时生成的值从1开始,每次增长1。
// build our order object without an id Order order = new Order("Jim Sanders", 12.34); ... orderDao.create(order); System.out.println("Order id " + order.getId() + " was persisted to the database"); // query for the order with an id of 1372 order = orderDao.queryForId(1372); if (order == null) { // none of the order rows have an id of 1372 }
在上面的代码示例中,一个order构造用name和amount两个属性。当把它传给DAO'的create方法时,id变量没有设置。它保存到数据库之后,ORMLite会把生成的id设置给id变量并且getId()方法在create方法返回后被order调用是有有效的。
注意:其他特殊变量类型也是可以生成的,比如UUID。你可以使用allowGeneratedIdInsert变量进行设置,允许向表中插入拥有已经设置过或没有设置过id的对象。根据数据库类型,你可能不能改变自动生成id字段的值。
2.8.3 成员变量使用generatedIdSequence
一些数据库使用一种被称为序列号生成器的东西来提供生成id的值。如果你把generatedId = true用在这些数据库上,序列名将会被ORMLite自动生成。如果这样,你需要设置序列名来匹配已经存在的schema,你可以使用generatedIdSequence序列名的值。
public class Order { @DatabaseField(generatedIdSequence = "order_id_seq") private int id; ... }
在上面的示例中,虽然id值再次自动生成,但是仍然使用序列名:order_id_seq 。如果你使用的数据库不支持序列,那么这将会抛出一个异常。
注意:根据数据库类型,你不能改变自动生成id字段的值。
2.9 DAO 的使用
下面通过使用DAO方法简单完成数据库操作:
①创建并且持久化对象到数据库。
插入一条和对象相关的记录到数据库中。
Account account = new Account(); account.name = "Jim Coakley"; accountDao.create(account);
②查询它的id字段
如果对象有个id成员变量通过注解定义的,我们可以通过它的id在数据库中查找一个对象。
Account account = accountDao.queryForId(name); if (account == null) { account not found handling ... }
③更新与对象相关的数据库记录
如果你在内存中改变一个对象的成员变量,你必须调用update把它持久化到数据库。这需要一个id字段。
account.password = "_secret";
accountDao.update(account);
④当数据库有改变,刷新对象
如果一些与内存中对象相关的数据库实体发生了改变,你就需要刷新来得到最新的存储对象。这需要一个id字段。
accountDao.refresh(account);
⑤从数据库中删除数据
从数据库删除与对象关联的记录。一旦对象从数据库删除,你可以继续使用内存中的对象但是任何的更新或者刷新都很可能失败。这需要一个id字段。
accountDao.delete(account);
⑥遍历表中所有记录
DAO也有迭代器,所以你可以简单的执行数据库中所有的记录。
// page through all of the accounts in the database for (Account account : accountDao) { System.out.println(account.getName()); }
注意:你必须遍历迭代器所有的条目来关闭底层的SQL对象。如果你没有通过循环走所有的途径,那么ORMLite不知道关闭底层对象,并且一个到数据库的连接可能泄露,如果更迟一些垃圾回收器才获得它,那么它将被迫关闭,这会在你的代码中产出漏洞。使用下面的try ... finally模板包住迭代器。
例如,下面是一个不好的循环模板。
for (Account account : accountDao) { if (account.getName().equals("Bob Smith")) { // you can't return, break, or throw from here return account; } }
如果一个异常仍出循环这种bug照样会发生,所以如果这样的话循环就不应该被使用。这也是一个用迟加载收集的一个案例。
⑦直接使用迭代器
你也可以直接使用迭代器,因为用循环并不是最佳选择。这种方式允许你使用更好的try ... finally模板。
CloseableIterator<Account> iterator = accountDao.closeableIterator(); try { while (iterator.hasNext()) { Account account = iterator.next(); System.out.println(account.getName()); } } finally { // close it at the end to close underlying SQL statement iterator.close(); }
⑧获得"wrapped iterable"
你也可以使用"wrapped iterable",它允许你在finally中使用close而一直使用循环。
CloseableWrappedIterable<Account> wrappedIterable = accountDao.getWrappedIterable(); try { for (Account account : wrappedIterable) { ... } } finally { wrappedIterable.close(); }