[翻译] ORMLite document -- How to Use Part (一)


前言

此文档翻译于第一次学习 ORMLite 框架,如果发现当中有什么不对的地方,请指正。若翻译与原文档出现任何的不相符,请以原文档为准。原则上建议学习原英文文档。

----------------------------------------------------------------------------------------------

 二、如何使用

2.1 配置 POJO

配置你的 POJO,使其能持久化到数据库,你需要做到下面的几件事:

  1. 添加 @DatabaseTable 注解到每个需要持久化的 POJO 顶部,也可以使用 @Entity。
  2. 添加 @DatabaseField 注解到每个需要持久化的成员属性上面,也可以使用 @@Column.
  3. 保证每个需要持久化的 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个字段:

  1. name 字段是一个字符串,同时也是数据库记录的标识(主键)。
  2. 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都有两个泛型参数:

  1. 我们用 DAO 持久化的类。
  2. 用于标记数据库行的 ID 字段,如果这个类没有 ID 字段,可以使用 Object 或者 void 作为第二个参数。例如,在上述Account类中,"名称"字段是 ID 列 (id = true) 所以 ID 类是String.

创建 DAO 的最简单的方式是使用 DaoManager 类的静态 方法 createDao。例如:

Dao accountDao =
  DaoManager.createDao(connectionSource, Account.class);
Dao 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 {
    // empty wrapper, you can add additional DAO methods here
}

 然后在实现中,你应该扩展BaseDaoImpl基类。这里是您的 DAO 接口的示例实现:

/** JDBC implementation of the AccountDao interface. */
public class AccountDaoImpl extends BaseDaoImpl
  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 (二)