[翻译] ORMLite document -- How to Use Part (一)
前言
此文档翻译于第一次学习 ORMLite 框架,如果发现当中有什么不对的地方,请指正。若翻译与原文档出现任何的不相符,请以原文档为准。原则上建议学习原英文文档。
----------------------------------------------------------------------------------------------
二、如何使用
2.1 配置 POJO
配置你的 POJO,使其能持久化到数据库,你需要做到下面的几件事:
- 添加 @DatabaseTable 注解到每个需要持久化的 POJO 顶部,也可以使用 @Entity。
- 添加 @DatabaseField 注解到每个需要持久化的成员属性上面,也可以使用 @@Column.
- 保证每个需要持久化的 POJO 有 protect,或 public 修饰的无参的构造器。
2.1.1 添加 ORMLite 注解
从 Java5 开始支持的 annotations 作为一种特殊的代码标记,可以提供对于类,方法,字段的元信息。若要指定哪些类和字段来存储在数据库中,ORMLite 支持其自己的注释 (@DatabaseTable
和 @DatabaseField
) 或使用 Java 扩展包 javax.persistenc 下提供的标准注解
。请参阅使用标注批注。注解是最简单的方法来配置您的类,你也可以使用 Java 代码或 Spring XML 来配置类。请参见类配置一节.
对于 ORMLite 注解,每个需要持久化到数据库的 Java 类,你需要添加 @DatabaseTable
注解到类的上方。每一个被这个注解标注的 POJO 都将被持久化到数据库,例如:
@DatabaseTable(tableName = "accounts") public class Account { …
@DatabaseTable 注解有一个可选的参数 tablename 用来指定当前的 POJO 对应的数据库的表名。如果未指定,默认情况下使用的类名称。对于上面的示例中的每个 Account
对象将保持作为数据库中的 accounts
表中的行。如果未指定 tableName 参数
,会使用 account
表。
对于高级的用户可能想要添加一个 daoClass 参数指定 DAO 对象,这个 daoClass 参数指定的 DAO, 将被 DaoManager 实例化。请参阅DaoManager。
此外,对于每一个 POJO,你需要添加 @DatabaseField 注解到每个需要保存到数据库的成员变量上。每个成员变量将作为数据库表中的记录的列。例如:
@DatabaseTable(tableName = "accounts") public class Account { @DatabaseField(id = true) private String name; @DatabaseField(canBeNull = false) private String password; …
在上面的示例中,accounts 表中的没条记录有2个字段:
- name 字段是一个字符串,同时也是数据库记录的标识(主键)。
- password 字段是一个字符串,同时不能为空。
@DatabaseField 注解还可以设置以下的一些属性,该表没有对照翻译(详细属性介绍请看添加 ORMLite 注解):
Name | Type | Description |
columnName | String | 字段在数据库中的对应列名,默认为字段名 |
dataType | DataType. | 字段在数据库中的对应列的数据类型,默认为当前字段的类型在数据库的对应类型。请参阅Persisted Data Types |
defaultValue | String | 列不设值时的默认值,默认为空。 |
width | Integer | 主要用于设置字符串的字段宽度,默认为0,表示使用数据库当前字段的默认宽。 |
canBeNull | Boolean | 字段是否可以被设置为null,默认为 true。 |
id | Boolean | 用于指定持久化到数据库的的主键, 一个 POJO 中只有一个属性可以设置为 true,如果通过 Id 进行删除,更新,查找等操作,这个属性必须设置,@id、@generatedId、@generatedIdSequence 这三个注解在一个POJO中只能设置一个。如果你自动生成主键,你也可以使用 @GeneratedValue 注解。默认为 false |
generatedId | Boolean | 是否自动生成主键。一个 POJO 中只有一个属性可以设置为 true。当 DataType 指定为 DataType.UUID时,可以产生UUId。索引名为 tableName_columnName_seq。 |
generatedIdSequence | String | 同 @generatedId,但可以指定特殊的索引名称,默认为空。 |
foreign | Boolean | 用于设置一对多的外键关联,被当前注解标记的属性不能是基本数据类型,且被引用的这个 POJO 对象必须有主键字段(@id, @generatedId, @generatedIdSequence)被储存在当前的表中。 |
useGetSet | Boolean | 是否通过 get()、set() 方法访问属性,默认为 false,使用反射机制直接访问。 |
unknownEnumName | Enum | 对于一个枚举类型的属性,如果数据库中返回的值找不到对应的 Enum,将使用这个值,如果没有设置,默认将抛出 SQLException。 |
throwIfNull | Boolean | 如果对于该属性,数据库没有返回值,将抛出异常。默认为 false,如果数据库返回null,将属性设置为初始值 0 (false,null,等等) ,只支持基本数据类型。 |
persisted | Boolean | 是否存储当前属性到数据库对应的列。默认为 true。 |
format | String | 对特定格式数据的格式化信息。只支持数据类型 DATE_STRING、STRING_BYTES。 |
unique | Boolean | 唯一性约束。默认为 false |
uniqueCombo | Boolean | 联合唯一性约束,表中该行的所有已标记的字段的唯一性约束。默认为 false。 |
index | Boolean | 是否对该属性对于的列建立索引。 默认为 false,如果为 true,将建立 cloumnName_idx 的索引。 |
uniqueIndex | Boolean | 是否对该属性对应的列建立唯一索引。默认为 false。如果你只是想确保唯一性,可以使用 @unique。 |
indexName | String | 为该属性对应的列建立的索引名。 |
uniqueIndexName | String | 是否对该属性对应的列建立唯一索引名。 |
foreignAutoRefresh | Boolean | 是否自动对查询中的外键做字段更新。默认为 false 。 |
maxForeignAutoRefreshLevel | Integer | 对 @foreignAutoRefresh 可能产生的无限递归的补偿。设置外键对象字段刷新的层级。 |
allowGeneratedIdInsert | Boolean | 是否使用手动设置的 ID 覆盖自动生成 ID,默认为false。 |
columnDefinition | String | 定义该属性对应的列创建数据库时的字段的定义语句。 |
foreignAutoCreate | Boolean | 在保存一个有外键的对象时,是否自动保存关联对象。 |
version | Integer | 行版本号 |
foreignColumnName | String | 外键列名,当关联对象的外键列不是 ID 时,可以使用该属性设置。 |
2.1.2 添加 javax.persistence 注解
你可以使用 javax.persistence 包下的 Java 标准注释用来取代 ORMList 定义的注释。你可以使用 javax.persistence 包下的 @Entity 来替代 @DatabaseTable 注释,例如:
@Entity(name = "accounts") public class Account { …
@Entity 有个可选参数 name 用来指定表名,如果没有设置该属性,将默认使用类名作为表名。
你也可以在每个属性上使用 javax.persistence
注释: @Column
、 @Id
、 @GeneratedValue
、 @OneToOne
、 @ManyToOne
、 @JoinColumn
和@Version,而不是@DatabaseField。例如:
@Entity(name = "accounts") public class Account { @Id private String name; @Column(nullable = false) private String password; …
支持的 javax.persistence 有以下这些:
Annotation | Name | Type | Description |
@Entity | 指定当前类所对应的数据库表格。 | ||
name | String | 指定类所对应的表,如未指定,默认使用类名。 | |
@Column | 指定某一属性对应的数据库列。 | ||
name | String | 指定类所对应的表,如未指定,默认使用类名。 | |
length | Integer | 指定数据库字段的长度。也许仅适用于字符串和某些数据库类型。默认值为 255。和 @DatabaseField 注释的 width 字段相同。 |
|
nullable | Boolean | 是否可以为空。默认为 true,和 @DatabaseField 注释中的 canBeNull 字段相同 |
|
unique | Boolean | 唯一性约束,和 @DatabaseField 注释的 unique 字段相同。 |
|
@id | 指定某一属性对应的数据库列为主键。 | ||
@GeneratedValue | 和 @id 共用, 定义生成主键的值。 | ||
@OneToOne or @ManyToOne | 外键 | ||
@JoinColumn | |||
name | String | 设置属性的列名称。和 @Column{name=...} 相同。 |
|
nullable | Boolean | 是否可以为空。默认为 true,和 @Column{nullable=...} 相同。 | |
@Version | 版本号 |
2.1.3 添加无参的构造函数
在添加完类和属性的注释之后,你还需要保证有一个被 protect 或 public 的无参的构造器。当 ORMLite 返回一个查询的对象时,ORMLite 使用 Java 反射调研构造器返回对象。
Account() { // all persisted classes must define a no-arg constructor // with at least package visibility }
所以你最后一个例子拥有注释与构造函数的Account 类看起来应该是这样:
@DatabaseTable(tableName = "accounts") public class Account { @DatabaseField(id = true) private String name; @DatabaseField(canBeNull = false) private String password; … Account() { // all persisted classes must define a no-arg constructor // with at least package visibility } … }
2.2 可持久化的数据类型
下面的这些 Java 类型可以被 OEMLite 持久化到数据库。数据库的类型转换函数可以在把这些类型转换成 SQL 类型:
DataType | SQL Type | Description |
DataType.STRING | VARCHAR | String |
DataType.LONG_STRING | LONGVARCHAR | String |
DataType.STRING_BYTES | VARCHAR | String -->byte[] --> VARCHAR |
DataType.BOOLEAN or DataType.BOOLEAN_OBJ | BOOLEAN | |
DataType.DATE | TIMESTAMP | |
DataType.DATE_LONG | LONG | |
DataType.BYTE or DataType.BYTE_OBJ | TINYINT | byte or Byte --> TINYINT |
DataType.BYTE_ARRAY | VARBINARY | byte[] --> VARBINARY |
DataType.CHAR or DataType.CHAR_OBJ | CHAR | char or Character --> CHAR |
DataType.INTEGER or DataType.INTEGER_OBJ | INTEGER | short or Short --> INTEGER |
DataType.LONG or DataType.LONG_OBJ | BIGINT | long or Long --> BIGINT |
DataType.FLOAT or DataType.FLOAT_OBJ | FLOAT | float or Float --> FLOAT |
DataType.SERIALIZABLE | VARBINARY | Serializable |
DataType.ENUM_STRING | INTEGER | |
DataType.UUID | VARCHAR | UUID |
DataType.BIG_INTEGER | VARCHAR | BigInteger |
DataType.BigDecimal | VARCHAR | BigDecimal |
DataType.BIG_DECIMAL_NUMERIC | NUMERIC | BigDecimal |
DataType.DATE_TIME | ||
DataType.SQL_DATE | TIMESTAMP | java.sql.Date |
DataType.TIME_STAMP | TIMESTAMP | java.sql.Timestamp |
2.3 连接源
关于连接源,Android 用户应该看请参阅 Android 使用说明 一节。
为了使用数据库和 DAO 对象,您将需要配置 JDBC 调用 DataSource (见javax.sql.DataSource类) 和 ORMLite 调用 ConnectionSource。ConnectionSource 是一个连接到物理数据库的工厂类。
这里是一个示例,创建一个简单的连接源单列:
// single connection source example for a database URI ConnectionSource connectionSource = new JdbcConnectionSource("jdbc:h2:mem:account");
此外,这个包下有一个相对简单的连接池类 JdbcPooledConnectionSource。当数据库连接被释放,而不是被关闭,被添加到内部列表中,他们可以在以后重复使用。当没有休眠的 connection 可以使用是就创建一个新的。JdbcPooledConnectionSource 是同步的,可以在多线程中使用。他可以设置关闭连接前的最大的空闲连接数量和最最长存活时间。
// pooled connection source JdbcPooledConnectionSource connectionSource = new JdbcPooledConnectionSource("jdbc:h2:mem:account"); // only keep the connections open for 5 minutes connectionSource.setMaxConnectionAgeMillis(5 * 60 * 1000);
JdbcPooledConnectionSource 拥有一个一直存活的线程,时常 ping 各个休眠的连接,关闭那些长时间没有验证通过的连接,保证连接的有效性。你还可以启用测试,在从连接池获取这个 connection 之前。
// change the check-every milliseconds from 30 seconds to 60 connectionSource.setCheckConnectionsEveryMillis(60 * 1000); // for extra protection, enable the testing of connections // right before they are handed to the user connectionSource.setTestBeforeGet(true);
当您完成您的 ConnectionSource
时,要调用 close()
方法来关闭任何潜在的连接。下面的模式类似建议。
JdbcConnectionSource connectionSource = new JdbcPooledConnectionSource("jdbc:h2:mem:account"); try { // work with the data-source and DAOs … } finally { connectionSource.close(); }
有许多其他高性能,更健壮的扩展数据源管理器可以来替换,你可以直接实例化自己,并将其包装在委托给它的DataSourceConnectionSource
类。
// basic Apache data source BasicDataSource dataSource = new BasicDataSource(); String databaseUrl = "jdbc:h2:mem:account"; dataSource.setUrl(databaseUrl); // we wrap it in the DataSourceConnectionSource ConnectionSource connectionSource = new DataSourceConnectionSource(dataSource, databaseUrl);
当你使用完 ConnectionSource
时,要调用 close()
方法来关闭任何潜在的连接。建议使用类似下面的模式:
JdbcConnectionSource connectionSource = new JdbcPooledConnectionSource("jdbc:h2:mem:account"); try { // work with the data-source and DAOs … } finally { connectionSource.close(); }
很不幸,DataSource 接口没有关闭方法,所以你使用 DataSourceConnectionSource 你必须关闭底层数据源,通过操作 DataSourceConnectionSource 上的 close() 方法。
2.4 设置 DAOs
一旦你标注了注解类并且定义了你的 ConnectionSource,你就需要创建一个DAO(Data Access Object,这个类中包含对 POJO 的所有的数据库操作。每个DAO都有两个泛型参数:
- 我们用 DAO 持久化的类。
- 用于标记数据库行的 ID 字段,如果这个类没有 ID 字段,可以使用 Object 或者 void 作为第二个参数。例如,在上述
Account
类中,"名称"字段是 ID 列 (id = true) 所以 ID 类是String
.
创建 DAO 的最简单的方式是使用 DaoManager 类的静态 方法 createDao。例如:
Dao<Account, String> accountDao = DaoManager.createDao(connectionSource, Account.class); Dao<Order, Integer> orderDao = DaoManager.createDao(connectionSource, Order.class);
注意:你需要内置 ORMLite 功能, 你可以使用 DaoManager.createDao() 方法创建你自己的 DAO 类,他们可以被再次利用而不是再次生成。创建一个 DAO 是一个昂贵的操作,如果可能的话应该重用 DAOs 为有限的资源 (如手机) 的设备。
如果你想更好的类层次的结构,或者你想要添加更多的方法到你的 DAO 中,你应该考虑定义一个接口,它继承自Dao接口。这个接口不是必需的,但是他说一种好的模式,这样你在JDBC持久化上用的代码会更少。下面是一个相当于本手册前面章节 Account 类的 DAO 接口的示例:
/** Account DAO which has a String id (Account.name) */ public interface AccountDao extends Dao<Account, String> { // empty wrapper, you can add additional DAO methods here }
然后在实现中,你应该扩展BaseDaoImpl
基类。这里是您的 DAO 接口的示例实现:
/** JDBC implementation of the AccountDao interface. */ public class AccountDaoImpl extends BaseDaoImpl<Account, String> implements AccountDao { // this constructor must be defined public AccountDaoImpl(ConnectionSource connectionSource) throws SQLException { super(connectionSource, Account.class); } }
要使用你自定义的 DAO 类,你需要将 daoClass
字段添加到 @DatabaseTable
上相应的实体类:
@DatabaseTable(daoClass = AccountDaoImpl.class) public class Account { … }
这是你需要做的所有的事,如果你需要定义一个自己的 DAO 类。如果有不需要不在基类中提供的特殊操作,你可以自由的将更多的方法添加到你的 DAO 接口和实现中。接口和实现,如果有需要不由道基类提供的特定操作。
如果你正在使用一个自定义的 DAO 一定要将 daoClass
参数添加到的您自定义的 DAO 类的 @DatabaseTable
注释。这被 DaoManager 内部实例化 Dao 时使用,请参阅DaoManager。
2.5 支持的数据库
ORMLite 支持以下数据库口味。他们有的需要遵循一些特定文档。请参阅 Supported Databases
- MySQL
- Postgres
- H2
- SQLite
- Android SQLite
- HSQLDB
- Microsoft SQL Server
- Netezza
- ODBC
2.6 整合
有一个被 annotation 标注的,添加了无参构造函数的 POJO 类,创建你的 ConnectionSource
,并定义自己的 DAO 类。你准备开始坚持和查询数据库对象。如果你想要运行该示例,你需要下载和 H2 jar 文件添加到您的类路径,。请参阅H2 主页.
// h2 by default but change to match your database String databaseUrl = "jdbc:h2:mem:account"; JdbcConnectionSource connectionSource = new JdbcConnectionSource(databaseUrl); // instantiate the dao with the connection source AccountDaoImpl accountDao = new AccountDaoImpl(connectionSource); // if you need to create the 'accounts' table make this call TableUtils.createTable(connectionSource, Account.class); // create an instance of Account Account account = new Account("Jim Coakley"); // persist the account object to the database accountDao.create(account); … // destroy the data source which should close underlying connections connectionSource.destroy();
-----------------------------------------------------------------------------
由于本文档篇幅过长,之后的部分请参阅[翻译] ORMLite document -- How to Use Part (二)