前言
由於第二章是整個文檔的核心,內容也很多,所以分次翻譯。下一章的內容會繼續本章接着翻譯。
-------------------------------------------------------------------------------------
2 如何使用
這一章進入到更多詳細地使用ORMLite的各種功能。
2.1 配置你的Class
為了配置你的class使其持久化,你需要做下面幾步:
①添加@DatabaseTable 注解到你每個需要持久化的類的頂部。你也可以用@Entity。
②添加@DatabaseField 注解到你需要持久化的字段的上面。你也可以使用@Column和其他的。
③為每個class添加一個無參的構造器,並且構造器在包內是可見的。
2.1.1 添加ORMLite 注解
自從java5開始,注解是有效的特殊代碼標識,它提供meta信息包括類、方法或成員變量。把指定的類和成員變量存入數據庫,ORMLite既支持它自己的注解(@DatabaseTable和 @DatabaseField)也支持很多來自javax.persistence包中標准的注解。注解是配置你的class最簡單的方式,當然你也可以使用java代碼或者Spring xml(Spring是個框架,更多信息google一下)對class進行配置。
用ORMLite注解,對每個你想要持久化到SQL數據庫的java類你都需要添加@DatabaseTable注解到public class 這一行的正上方。每個被這些注解標記過的class都將持久化到它自己的數據庫表中。例如:
@DatabaseTable(tableName = "accounts") public class Account { ...
@DatabaseTable注解可以有個可選的tableName 參數,也就是這個類對於的表名。如果沒有特別指出,那么這個類名將默認作為表名。使用示例中的Account的對象都將會作為一條記錄持久化到數據庫名為account的表中。這將會在DaoManager實例化內部Dao的時候使用到。
除此之外,對於每個class你需要添加@DatabaseField注解到class的成員變量上,這個類是需要持久化到數據庫的。每個成員變量都將被作為數據庫中記錄的一個字段進行持久化。示例:
@DatabaseTable(tableName = "accounts") public class Account { @DatabaseField(id = true) private String name; @DatabaseField(canBeNull = false) private String password; ...
①name字段,它是一個字符串並且是數據庫中記錄的唯一標識(主鍵)。在上面的示例中,account表的每條記錄都有兩個字段:
②password字段,它也是一個字符串,它不能為null。
@DatabaseField注解可以用下面的一些成員:(對常用的字段進行翻譯,其他的參考原文)
常用的注解 |
||
成員名 |
數據類型 |
描述 |
columnName |
String |
數據庫的列名。如果你沒有設置這個成員名,會用標准的形式代替它。 |
dataType |
字段的數據類型。通常情況下,數據類型是從java類的成員變量獲取的,並不需要進行特殊指出。它相當於是SQL的數據類型。 |
|
defaultValue |
String |
當我們在表中創建新的記錄時的一個字段的默認值。默認情況下是沒有這個值的。 |
width |
Integer |
字段的寬度,主要用於字符串字段。默認是0,意味着采用默認的數據類型和具體的數據庫的默認情況。對於字符串以為在255個字符即使有些數據庫並不支持。 |
canBeNull |
Boolean |
字段是否能被分配null值。默認是true。如果你設置成false,那么你每次在數據庫中插入數據是都必須為這個字段提供值。 |
id |
Boolean |
這個字段是否是id,默認是false。在一個class中只有一個成變量可以有這個值。id字段是一條記錄的唯一標識而且是必需的,只有generatedId和 generatedIdSequence其中之一。 |
generatedId |
Boolean |
字段是否自動增加。默認為false。類中的一個成員變量設置了這個值,它告訴數據庫每添加一條新記錄都自動增加id。當一個有generatedid的對象被創建時使用Dao.create()方法,數據庫將為記錄生成一個id,它會被返回並且被create方法設置進對象。 |
generatedIdSequence |
String |
序列編號的名字,這個值在生成的時候會被使用。和generatedId相似,但是你能夠指定使用的序列名稱。默認是沒有的。一個class中只有一個成員變量可以設置這個值。這僅僅在數據庫需要序列生成id時才需要它。如果你選擇使用generatedId代替它,那么代碼將自動增加序列名。 |
其他注解 |
||
foreign |
throwIfNull |
|
useGetSet |
persisted |
|
unknownEnumName |
format |
|
uniqueIndexName |
allowGeneratedIdInsert |
|
foreignAutoRefresh |
columnDefinition |
|
unique |
uniqueIndex |
|
uniqueCombo |
indexName |
|
index |
uniqueIndexName |
|
version |
maxForeignAutoRefreshLevel |
|
foreignColumnName |
foreignAutoCreate |
2.1.2 使用javax.persistence 注解
取代使用ORMLite注解,你可以使用來自javax.persistence包的更多的標准JPA注解。取代@DatabaseTable注解,你可以使用javax.persistence @Entity注解。示例:
@Entity(name = "accounts") public class Account { ...
@Entity注解有個可選的name參數,它用於指定表名。如果沒有指定,類名將是默認的表名。
在每個成員變量中取代使用@DatabaseField注解,你可以用javax.persistence注解: @Column, @Id, @GeneratedValue, @OneToOne,@ManyToOne, @JoinColumn, and @Version. 示例:
下面這些javax.persistence注解和字段都支持:
注解 |
注解屬性 |
描述 |
@Entity |
name |
用於關聯的數據庫表的名字。如果沒有設置那么類名將被作為表名。 |
@Column |
name |
用作表字段的名字。如果沒有設置那么變量名將作為字段名。 |
length |
數據庫表字段的長度。可能只有應用在字符串並且只被某些數據庫類型支持。默認是255。 |
|
nullable |
設置成true,那么這個字段允許插入null值。 |
|
unique |
添加一個約束,它在表中必須是唯一的。 |
|
@GeneratedValue |
用於定義一個自動增長的id值,它只能用於添加到@Id注解。
|
|
@OneToOne |
成員變量使用這些注解后會被認為是外鍵字段。 ORMLite沒有實現多個或一個關系,它也不能使用任何注解成員。它只能使用這些注解的兩者之一來表明它是一個外鍵。 |
|
@ManyToOne |
||
@JoinColumn |
name |
設置成員變量的列名(字段名)。 |
nullable |
設置成true,那么這個字段允許插入null值。 |
|
@Version |
使用它將會把short, integer, long, Date這些類型的成員轉化成版本成員。 |
如果@Column注解在成員變量上用了一個未知的類型,那么它將被認為是序列化類型字段並且這個對象需要實現java.io.Serializable。
2.1.3 添加無參構造器
在你給class添加了注解字段后,你也需要添加一個無參的包內可見的構造器。當一個對象在查詢中被返回時,ORMLite使用java反射機制構造一個對象並且構造器需要被調用。所以你最終的示例擁有注解和構造器的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類型能夠被ORMLite持久化到數據庫。數據庫具體編碼幫助SQL類型和數據庫具體持有類型的相互轉化。
(具體的類型相互轉化在此就不作介紹了,參見原文)。
2.3 連接源
注意:關於連接源,android用戶應該參見手冊中Android詳細文檔。
為了使用數據庫和DAO對象,你需要配置JDBC調用數據源和ORMLite調用連接源。連接源是連接物理SQL數據庫的一個工廠。這里是創建簡單、單連接的代碼示例:
// single connection source example for a database URI ConnectionSource connectionSource = new JdbcConnectionSource("jdbc:h2:mem:account");
這包中也包括了類JdbcPooledConnectionSource ,它是一個相對簡單的連接池的實現。一個數據庫連接已經釋放而成為關閉,之后向他們添加內部列表他們都會拒絕。只有在沒有休眠的可用的連接時,新的連接才需要創建。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一下池中空閑的每個連接,目的是為了確認他們是有效的,關閉的那個就不再有效。在你從池中取得連接之前你也可以測試連接是否有效。
// 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);
有很多其他額外的數據,他們能夠被使用,包括很多更強大甚至高性能的池連接管理器。你可以用你自己直接封裝的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),它是一個擁有數據庫操作句柄的單一持久化類。每個DAO都有兩個泛型參數:①我們用DAO持久化的類,②id字段,它用於確定數據庫具體的記錄。如果你的類沒有ID字段,你可以放入Object或者Void作為第二個參數。例如,在上面的Account類,成員變量name是ID字段,所以ID類是String。
創建DAO最簡單的方式是使用DaoManager類的靜態方法createDao。示例:
Dao<Account, String> accountDao = DaoManager.createDao(connectionSource, Account.class); Dao<Order, Integer> orderDao = DaoManager.createDao(connectionSource, Order.class);
注意:你需要使用DaoManager.createDao()方法創建你自己的DAO類,所以如果內置ORMLite功能是需要他們,他們可以被再次利用並且不能再次生成。創建DAO會有昂貴的操作代價並且很多設備有資源限制(比如移動設備應用),盡可能重復使用DAO。
如果你想更好的類層次的機構或者你需要添加附加的方法套你的DAOs中,你應該考慮定義一個接口,它繼承自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 { public AccountDaoImpl(ConnectionSource connectionSource) throws SQLException { super(connectionSource, Account.class); } }
那就是你需要定義你的DAO類。如果有特殊的操作需要並且Dao基類沒有提供的方法,你可以自由添加更多方法到你的DAO接口和添加到你的實現中。
注意:如果你正在使用一個定制的DAO,然后確保添加daoClass參數到你自己定制的DAO類的@DatabaseTable注解。這會被DaoManager用於內部實例化DAO。
2.5 支持的數據庫
ORMLite支持下面的數據庫。這些數據庫中的某些數據庫有具體需要遵守的文檔。(下面給出支持的數據庫,具體文檔參見官方文檔)
支持的數據庫 |
|||||
MySQL |
H2 |
Android SQLite |
HSQLDB |
Netezza |
DB2 |
Postgres |
SQLite |
Microsoft SQL Server |
Derby |
ODBC |
Oracle |
2.6 整合
這樣你有一個注解對象被持久化,添加一個無參構造器,創建你的ConnectionSource並且定義你的DAO類。你已經開始持久化和查詢你的數據庫對象了。你需要下載並且添加H2 jar文件到你的classPath中,如果你想讓這個示例跑起來的話。下面是整合的代碼:
// 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();
PS: 第二章還在翻譯中... 文中有不妥之處希望讀者提出,轉載請注明出處。