刚刚入手联想管家怎么测网速P8,怎样开启网速显示玖双

7323人阅读
Android进阶(9)
SQLite在多线程并发访问的应用
最近遇到个SQLite的问题把我卡住了小半天,最后总结一句话:SQLite不支持多线程
研究一下,发现有以下2种方案可行
1.首先当多个线程并发操作同一个数据库,同时存在insert、delete和select操作,数据是不安全的,在Android内置的SQLite中也是不允许的,这时会造成冲突异常。不允许多线程,则必须实现多线程同步
多线程同步锁的访问SQLite使用:始终让整个Application保持一个database连接,这样的话即使多线程同时访问sqlite,database对象使用java锁会保持访问的序列化。我们一般都是用SQLHelper来管理数据库,而一个Helper实例会产生一个database连接,所以我们只需要让整个Application产生一个SQLHelper的实例就行了
public class SQLHelper extends SQLiteOpenHelper {
private static final int VERSION_CODE = 1;
private static SQLH
* 同步锁 +单例模式获得唯一数据库帮助类实例
* @param context
public synchronized static SQLHelper getInstance(Context context) {
if (helper == null) {
helper = new SQLHelper(context);
private SQLHelper(Context context) {
super(context, &person.db&, null, VERSION_CODE);
private SQLHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, VERSION_CODE);
public void onCreate(SQLiteDatabase db) {
Log.i(&sqlite&, &数据库被创建&);
// 创建数据库表
String sql = &create table t_student(_id integer primary key autoincrement,id integer,name varchr(20),age int,address varchr(40))&;
db.execSQL(sql);
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String sql = &drop table t_student&;
db.execSQL(sql);
public synchronized void close() {
super.close();
在程序的入口处,Application中产生一个SQLHelper的实例,注意此处的onTerminate()不一定每次退出时都能执行,建议在首页(主activity)的onDestory()方法中调用dbHelper.close();来关闭数据库连接
public class MyApplication extends Application {
private DBHelper dbH
public void onCreate() {
super.onCreate();
context = getApplicationContext();
dbHelper = DBHelper.getInstance(context);
public void onTerminate() {
super.onTerminate();
dbHelper.close();
总结:多线程 同步锁的方式访问SQLite,保证了同一个时刻SQLite 只有一个连接,多个线程排队依次访问数据库,完美解决了冲突问题。
这个问题确实让我困扰了小半天,自己摸索的确是比较痛苦,最后在国外一片帖子中看到这么一段描述,有种豁然开朗的感觉。
Inserts, updates, deletes and reads are generally OK from multiple threads, but Brad's&is not correct.& You have to be careful with
how you create your connections and use them.& There are situations where your update calls will fail, even if your database doesn't get corrupted.
The basic answer.
The SqliteOpenHelper object holds on to one database connection.& It appears to offer you a read and write connection, but it really doesn't.& Call the read-only, and you'll get the write database connection regardless.
So, one helper instance, one db connection.& Even if you use it from multiple threads, one connection at a time.& The SqliteDatabase object uses java locks to keep access serialized.& So, if 100 threads have one db instance,
calls to the actual on-disk database are serialized.
So, one helper, one db connection, which is serialized in java code.& One thread, 1000 threads, if you use one helper instance shared between them, all of your db access code is serial.& And life is good (ish).
If you try to write to the database from actual distinct connections at the same time, one will fail.& It will not wait till the first is done and then write.& It will simply not write your change.& Worse, if you don’t call the
right version of insert/update on the SQLiteDatabase, you won’t get an exception.& You’ll just get a message in your LogCat, and that will be it.
So, multiple threads?& Use one helper.& Period.& If you KNOW only one thread will be writing, you MAY be able to use multiple connections, and your reads will be faster, but buyer beware.& I haven't tested that much.
Here's a blog post with far more detail and an example app.
&(Updated link 6/18/2012)&on GitHub
Gray and I are actually wrapping up an ORM tool, based off of his Ormlite, that works natively with Android database implementations, and follows the safe creation/calling structure I describe in the blog post.& That should be
out very soon.& Take a look.
In the meantime, there is a follow up blog post:
Also checkout the fork by2point0 of the previously mentioned locking example:
关于第二种方式,同样也能解决并发操作SQLite
2.“一个database&connect,既有查询又有更新(不同的statement,且不论顺序),执行完之后,不关闭,会产生一个扩展名为s3db-journal的(临时)文件,若再次使用该connect执行更新,则产生“unable&to&open&database&file”的异常。&所以,一个connect执行完之后要么close,要么自己处理临时文件。”毕竟不同设备的数据库文件存储路径有所区别,删除可能遇到文件路径错误,文件不存在等问题,所以推荐使用前者,执行完毕,立即关闭close()
public synchronized void close() {
super.close();
&注意:此处和上面案例恰恰相反,每次使用数据都要通过构造函数构造一个SQLHelper实例,如果每次使用同一个SQLHelper,那么关闭后就不能再打开数据库
Cursor cursor =
// helper = SQLHelper.getInstance(context);
//注意:此处和上面案例恰恰相反,每次使用数据都要通过构造函数构造一个sqlhelper实例
helper = new SQLHelper(context);
SQLiteDatabase db = helper.getReadableDatabase();
cursor = db.query(&t_student&, null, null, null, null, null, null);
} catch (Exception e) {
// TODO: handle exception
} finally {
helper.close(); // 用完立即关闭
总结:比较了这两种方法,测试过后,强烈推荐使用第一个,从性能的角度,第一种使用单例加同步锁的模式,全局只有一个SQLHelper对象,而第二种方式则是需要多次创建SQLHelper对象,然后关闭,性能远远低于单例的方式
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:128919次
积分:1975
积分:1975
排名:第19067名
原创:64篇
转载:42篇
评论:19条
(1)(2)(1)(1)(1)(6)(4)(3)(3)(6)(1)(1)(8)(4)(2)(7)(2)(6)(5)(6)(4)(6)(2)(7)(1)(12)(4)1181人阅读
Android(38)
首先介绍一下OrmLite:ORM Lite是把对象Java对象映射到关系型数据库的工具,为把Java对象持久化到SQL数据库提供简单的轻量化的功能。
Object Relational Mapping Lite (ORM Lite) provides some&simple, lightweight functionality for persisting Java objects
to SQL databases while avoiding the complexity and overhead of more standard ORM packages.
& & & &JPA(Java Persistence API)已经是JAVAEE持久化的标准,相关的产品中还有Hibernate。
本文以一个文章(article)的信息实例程序来展示如何使用ormlite for android的第三方组件来开发Sqlite的C[增加],R[查询],U[更新],D[查询]应用程序,以便更方便的对sqlite数据库的操作。我们先看下程序的结构图:
其中包com.strongunion.ormlite.model下Article.java为实体类,包com.strongunion.ormlite.services下DatabaseHelper.java为数据库辅助类,包com.strongunion.ormlite下的MainActivity.java是界面信息类。同时我们别忘了在根目录下创建一个libs的文件夹,把第三方组件包ormlite-android-版本号.jar
,ormlite-core-版本号.jar放到libs文件夹下就OK了。
Because of the lack of official support for
JDBC in Android OS, ORMLite makes direct calls to the Android database APIs to access SQLite databases. You should make sure that you have downloaded and are depending on the&ormlite-core.jar&and&ormlite-android.jar&files,
but&not&the&ormlite-jdbc.jar&version.
因为Android OS没有官方支持JDBC, 所以ORMLite可以直接通过APIs来访问SQLite数据库,所以我们不需要jdbc的jar包。
ORMLite的jar包下载地址和ORMLite的Home首页地址如下:
jar包下载地址:/releases/
ORMLite首页:/
Article的代码如下图:
package com.strongunion.ormlite.
import java.util.D
import com.j256.ormlite.dao.ForeignC
import com.j256.ormlite.field.DatabaseF
import com.j256.ormlite.field.ForeignCollectionF
import com.j256.ormlite.table.DatabaseT
@DatabaseTable
public class Article {
@DatabaseField(generatedId = true)
@DatabaseField
public String getContent() {
public void setContent(String content) {
this.content =
public Date getPublishedDate() {
return publishedD
public void setPublishedDate(Date publishedDate) {
this.publishedDate = publishedD
@DatabaseField
private Date publishedD
/*@ForeignCollectionField(eager = true)
ForeignCollection&Comment&*/
public Article() {
实体类代码的注意事项:你需要增加 @DatabaseTable 这个注解在每一个类的上边(这个注解是选的,可以更改表名),注解@DatabaseField 增加到每一个需要保存到数据库表中的属性的上边。
DatabaseHelper的代码如下:
package com.strongunion.ormlite.
import java.sql.SQLE
import android.content.C
import android.database.sqlite.SQLiteD
import android.util.L
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenH
import com.j256.ormlite.dao.D
import com.j256.ormlite.support.ConnectionS
import com.j256.ormlite.table.TableU
import com.strongunion.ormlite.model.A
import com.strongunion.
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public static final String TAG = &DatabaseHelper&;
public static final String DATABASE_NAME = &blog.db&;
public static final int DATABASE_VERSION = 1;
&private static DatabaseH
& * @param c
& * & & & & &A context to use when initializing the database for the first
& * & & & & &time.
& * @return A single instance of DatabaseHelper.
&public static synchronized DatabaseHelper getInstance(Context c) {
& &if (instance == null)
& & &instance = new DatabaseHelper(c);
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
* Returns the Database Access Object (DAO) for our Article class. It will create it or just give the cached
public Dao&Article, Integer& geAritcletDao() throws SQLException {
return getDao(Article.class);
* Returns the Database Access Object (DAO) for our Article class. It will create it or just give the cached
public Dao&Comment, Integer& geCommentDao() throws SQLException {
return getDao(Comment.class);
public void onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) {
TableUtils.createTable(connectionSource, Article.class);
TableUtils.createTable(connectionSource, Comment.class);
} catch (SQLException e) {
&Log.e(TAG, &Unable to create tables.&, e);
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
TableUtils.clearTable(connectionSource, Comment.class);
TableUtils.clearTable(connectionSource, Article.class);
onCreate(database, connectionSource);
} catch (SQLException e) {
Log.e(TAG, &Unable to update tables.&, e);
DataHelper代码的注意事项:我们的dataHelper继承OrmLiteSqliteOpenHelper这个类.
重写它的onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource)创建数据库方法和onUpgrade(SQLiteDatabase database,
ConnectionSource connectionSource, int oldVersion, int newVersion)数据库升级方法.&onCreate&creates the database when
your app is first installed while&onUpgrade&handles the upgrading of the database tables when you upgrade your app to a new version。
还根据不同的Model实体类来得到相应的Dao来对实体类进行操作(增删改查)等。
MainActivity 的代码如下:
package com.strongunion.
import java.sql.SQLE
import java.text.SimpleDateF
import java.util.D
import java.util.L
import android.app.A
import android.app.AlertD
import android.content.DialogI
import android.os.B
import android.util.L
import android.view.LayoutI
import android.view.M
import android.view.MenuI
import android.view.V
import android.view.ViewG
import android.widget.AdapterV
import android.widget.AdapterView.OnItemLongClickL
import android.widget.BaseA
import android.widget.EditT
import android.widget.ListV
import android.widget.TextV
import com.j256.ormlite.dao.D
import com.strongunion.ormlite.model.A
import com.strongunion.ormlite.services.DatabaseH
public class MainActivity extends Activity {
ListView articlesListV
private List&Article&
Dao&Article, Integer& articleD
DatabaseHelper dataH
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataHelper = DatabaseHelper.getInstance(this);
articleDao = dataHelper.geAritcletDao();
articles = articleDao.queryForAll();
System.out.println(&articles size=========& + articles.size());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
articlesListView = (ListView) findViewById(R.id.listView);
articlesListView.setEmptyView(findViewById(R.id.emptyView));
adpater = new ArticlesAdapter(articles);
articlesListView.setAdapter(adpater);
articlesListView.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView&?& parent, View view,
int position, long id) {
opearteArticlePrompt(position);
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_article_adding) {
addArticlePrompt();
return super.onOptionsItemSelected(item);
private void addArticlePrompt() {
View body = LayoutInflater.from(this).inflate(R.layout.article_dialog,
final EditText articleEditText = (EditText) body
.findViewById(R.id.article);
new AlertDialog.Builder(this)
.setTitle(&Add Article&)
.setView(body)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialogInterface, int i) {
String comments = articleEditText.getText()
.toString().trim();
if (!comments.equals(&&)) {
// insertComment(name, comments);
Article article = new Article();
article.setContent(comments);
article.setPublishedDate(new Date());
articleDao.create(article);
} catch (SQLException e) {
Log.d(&MainActivity&, &article add failure&);
queryListViewItem();
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialogInterface, int i) {
// do nothing
}).show();
private void opearteArticlePrompt(final int position) {
View body = LayoutInflater.from(this).inflate(R.layout.article_dialog,
final EditText articleEditText = (EditText) body
.findViewById(R.id.article);
final Article article = articles.get(position);
articleEditText.setText(article.getContent());
new AlertDialog.Builder(this)
.setTitle(&Opearate Article&)
.setView(body)
.setPositiveButton(R.string.modification,
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialogInterface, int i) {
String comments = articleEditText.getText()
.toString().trim();
if (!comments.equals(&&)) {
article.setContent(comments);
article.setPublishedDate(new Date());
articleDao.update(article);
} catch (SQLException e) {
Log.d(&MainActivity&, &article add failure&);
queryListViewItem();
.setNeutralButton(R.string.delete, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
articleDao.delete(article);
} catch (SQLException e) {
Log.d(&MainActivity&, &article add failure&);
queryListViewItem();
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialogInterface, int i) {
// do nothing
}).show();
private void queryListViewItem(){ &
& & & &try { &
& & & & & &//查询所有的记录项 &
& & & & & &articles = articleDao.queryForAll(); &
& & & & & &System.out.println(&articles 2 size=========& + articles.size());
& & & & & &adpater.setArticlesList(articles);
& & & & & &adpater.notifyDataSetChanged();
& & & &} catch (SQLException e) { &
& & & & & &e.printStackTrace(); &
& & & &} &
class ArticlesAdapter extends BaseAdapter{ &
& & & &private List&Article& articlesL &
& & & &public void setArticlesList(List&Article& articlesList) {
this.articlesList = articlesL
SimpleDateFormat formatter = new SimpleDateFormat(
& & & & & & & &&'Created on' M/d/yyyy h:mm a&);
& & & &public ArticlesAdapter(List&Article& students){ &
& & & & & &super(); &
& & & & & &this.articlesList = &
& & & &} &
& & & &@Override &
& & & &public int getCount() { &
& & & & & &return articlesList.size(); &
& & & &} &
& & & &@Override &
& & & &public Article getItem(int position) { &
& & & & & &return articlesList.get(position); &
& & & &} &
& & & &@Override &
& & & &public long getItemId(int position) { &
& & & & & & &
& & & &} &
& & & &@Override &
& & & &public View getView(int position, View convertView, ViewGroup parent) { &
& & & & & &ViewH &
& & & & & &if(convertView == null){ &
& & & & & & & &LayoutInflater mInflater = LayoutInflater.from(MainActivity.this);&
& & & & & & & &convertView = mInflater.inflate(R.layout.list_item, null); &
& & & & & & & &holder = new ViewHolder(); &
& & & & & & & &holder.content = (TextView)convertView.findViewById(R.id.list_complex_title); &
& & & & & & & &holder.publishedDate = (TextView)convertView.findViewById(R.id.list_complex_caption); &
& & & & & & & &convertView.setTag(holder); &
& & & & & &}else{ &
& & & & & & & &holder = (ViewHolder)convertView.getTag(); &
& & & & & &} &
& & & & & & &
& & & & &&
& & & & & &Article objStu = articlesList.get(position); &
& & & & & &holder.content.setText(objStu.getContent()); &
& & & & & &holder.publishedDate.setText(formatter.format(objStu.getPublishedDate())); &
& & & & & & &
& & & & & &return convertV &
& & & &} &
& &static class ViewHolder{ &
& & & &TextV &
& & & &TextView publishedD &
MainActivity的注意事项:MainActivity是应用的主界面,点击菜单中的“Add article”输入article的内容之后点击确定,可以增加一个Article。长按某个列表中的item,可以对一个article进行更改删除。
程序运行图解如下:
Step1,程序没有数据的时候界面:
Step2,增加一个Article的界面:
Step3,选中一个article,对这个article进行删除,更改的界面如下:
布局的内容比较简单,在这个就不贴代码了。
希望对大家有所帮助。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:54506次
积分:1052
积分:1052
排名:千里之外
原创:48篇
(2)(1)(2)(2)(2)(1)(1)(1)(4)(6)(1)(4)(7)(11)(4)(4)(1)(1)10906人阅读
android(151)
java(116)
由于第二章是整个文档的核心,内容也很多,所以分次翻译。下一章的内容会继续本章接着翻译。
-------------------------------------------------------------------------------------
2&如何使用
这一章进入到更多详细地使用的各种功能。
2.1&配置你的
为了配置你的使其持久化,你需要做下面几步:
①添加注解到你每个需要持久化的类的顶部。你也可以用。
②添加注解到你需要持久化的字段的上面。你也可以使用和其他的。
③为每个添加一个无参的构造器,并且构造器在包内是可见的。
2.1.1&添加注解
自从开始,注解是有效的特殊代码标识,它提供信息包括类、方法或成员变量。把指定的类和成员变量存入数据库,既支持它自己的注解(和&)也支持很多来自包中标准的注解。注解是配置你的最简单的方式,当然你也可以使用代码或者(是个框架,更多信息一下)对进行配置。
用注解,对每个你想要持久化到数据库的类你都需要添加注解到public&class&这一行的正上方。每个被这些注解标记过的都将持久化到它自己的数据库表中。例如:
@DatabaseTable(tableName = &accounts&)
public class Account {
@DatabaseTable注解可以有个可选的参数,也就是这个类对于的表名。如果没有特别指出,那么这个类名将默认作为表名。使用示例中的的对象都将会作为一条记录持久化到数据库名为的表中。这将会在实例化内部的时候使用到。
除此之外,对于每个你需要添加注解到的成员变量上,这个类是需要持久化到数据库的。每个成员变量都将被作为数据库中记录的一个字段进行持久化。示例:
@DatabaseTable(tableName = &accounts&)
public class Account {
@DatabaseField(id = true)
@DatabaseField(canBeNull = false)
①字段,它是一个字符串并且是数据库中记录的唯一标识(主键)。在上面的示例中,表的每条记录都有两个字段:
②字段,它也是一个字符串,它不能为。
@DatabaseField注解可以用下面的一些成员:(对常用的字段进行翻译,其他的参考原文)
常用的注解
columnName
数据库的列名。如果你没有设置这个成员名,会用标准的形式代替它。
字段的数据类型。通常情况下,数据类型是从类的成员变量获取的,并不需要进行特殊指出。它相当于是的数据类型。
defaultValue
当我们在表中创建新的记录时的一个字段的默认值。默认情况下是没有这个值的。
字段的宽度,主要用于字符串字段。默认是,意味着采用默认的数据类型和具体的数据库的默认情况。对于字符串以为在个字符即使有些数据库并不支持。
字段是否能被分配值。默认是。如果你设置成,那么你每次在数据库中插入数据是都必须为这个字段提供值。
这个字段是否是,默认是。在一个中只有一个成变量可以有这个值。字段是一条记录的唯一标识而且是必需的,只有和&其中之一。
generatedId
字段是否自动增加。默认为。类中的一个成员变量设置了这个值,它告诉数据库每添加一条新记录都自动增加。当一个有的对象被创建时使用方法,数据库将为记录生成一个,它会被返回并且被方法设置进对象。
generatedIdSequence
序列编号的名字,这个值在生成的时候会被使用。和相似,但是你能够指定使用的序列名称。默认是没有的。一个中只有一个成员变量可以设置这个值。这仅仅在数据库需要序列生成时才需要它。如果你选择使用代替它,那么代码将自动增加序列名。
throwIfNull
unknownEnumName
uniqueIndexName
allowGeneratedIdInsert
foreignAutoRefresh
columnDefinition
uniqueIndex
uniqueCombo
uniqueIndexName
maxForeignAutoRefreshLevel
foreignColumnName
foreignAutoCreate
2.1.2&使用注解
取代使用注解,你可以使用来自包的更多的标准注解。取代注解,你可以使用注解。示例:
@Entity(name = &accounts&)
public class Account {
@Entity注解有个可选的参数,它用于指定表名。如果没有指定,类名将是默认的表名。
在每个成员变量中取代使用注解,你可以用注解:&示例:
下面这些注解和字段都支持:
用于关联的数据库表的名字。如果没有设置那么类名将被作为表名。
用作表字段的名字。如果没有设置那么变量名将作为字段名。
数据库表字段的长度。可能只有应用在字符串并且只被某些数据库类型支持。默认是。
设置成,那么这个字段允许插入值。
&添加一个约束,它在表中必须是唯一的。
@GeneratedValue
用于定义一个自动增长的值,它只能用于添加到注解。
@OneToOne&
成员变量使用这些注解后会被认为是外键字段。&没有实现多个或一个关系,它也不能使用任何注解成员。它只能使用这些注解的两者之一来表明它是一个外键。
@ManyToOne
@JoinColumn
设置成员变量的列名(字段名)。
设置成,那么这个字段允许插入值。
使用它将会把这些类型的成员转化成版本成员。
如果Column注解在成员变量上用了一个未知的类型,那么它将被认为是序列化类型字段并且这个对象需要实现。
2.1.3&添加无参构造器
在你给添加了注解字段后,你也需要添加一个无参的包内可见的构造器。当一个对象在查询中被返回时,使用反射机制构造一个对象并且构造器需要被调用。所以你最终的示例拥有注解和构造器的类应该像这样:
@DatabaseTable(tableName = &accounts&)
public class Account {
@DatabaseField(id = true)
@DatabaseField(canBeNull = false)
Account() {
// all persisted classes must define a no-arg constructor
// with at least package visibility
2.2&持久化数据类型&
下面这些类型能够被持久化到数据库。数据库具体编码帮助类型和数据库具体持有类型的相互转化。
(具体的类型相互转化在此就不作介绍了,参见原文)。
2.3&连接源
注意:关于连接源,用户应该参见手册中详细文档。
为了使用数据库和对象,你需要配置调用数据源和调用连接源。连接源是连接物理数据库的一个工厂。这里是创建简单、单连接的代码示例:
// single connection source example for a database URI
ConnectionSource connectionSource =
new JdbcConnectionSource(&jdbc:h2:mem:account&);
这包中也包括了类,它是一个相对简单的连接池的实现。一个数据库连接已经释放而成为关闭,之后向他们添加内部列表他们都会拒绝。只有在没有休眠的可用的连接时,新的连接才需要创建。也是同步的并且可以用于多线程中。在连接关闭前它可以设置空闲连接的最大数和存活的最长时间。
// 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也有一个一直存活的线程,它偶尔一下池中空闲的每个连接,目的是为了确认他们是有效的,关闭的那个就不再有效。在你从池中取得连接之前你也可以测试连接是否有效。
// 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);
有很多其他额外的数据,他们能够被使用,包括很多更强大甚至高性能的池连接管理器。你可以用你自己直接封装的类来例举说明。
// 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);
当你用时,你想调用方法来关闭一些底层的连接。推荐像下面这样的模式。
JdbcConnectionSource connectionSource =
new JdbcPooledConnectionSource(&jdbc:h2:mem:account&);
// work with the data-source and DAOs
} finally {
connectionSource.close();
很不幸,接口没有关闭方法,所以你使用你必须关闭底层数据源,通过操作上的()方法。
一旦在你的类中有注解并且定义了你的,你就需要创建一个(),它是一个拥有数据库操作句柄的单一持久化类。每个都有两个泛型参数:①我们用持久化的类,②字段,它用于确定数据库具体的记录。如果你的类没有字段,你可以放入或者作为第二个参数。例如,在上面的类,成员变量是字段,所以类是。
创建最简单的方式是使用类的静态方法。示例:
Dao&Account, String& accountDao =
DaoManager.createDao(connectionSource, Account.class);
Dao&Order, Integer& orderDao =
DaoManager.createDao(connectionSource, Order.class);
注意:你需要使用方法创建你自己的类,所以如果内置功能是需要他们,他们可以被再次利用并且不能再次生成。创建会有昂贵的操作代价并且很多设备有资源限制(比如移动设备应用),尽可能重复使用。&
如果你想更好的类层次的机构或者你需要添加附加的方法套你的中,你应该考虑定义一个接口,它继承自接口。这个接口不是必需的,但是他说一种好的模式,这样你的代码在关联持久化的时候会更少。接下来是一个相当于本手册前面章节类的接口的示例:
/** 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
然后在实现中,你需要扩展基类。这里是个实现你的接口的示例。
/** 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);
那就是你需要定义你的类。如果有特殊的操作需要并且基类没有提供的方法,你可以自由添加更多方法到你的接口和添加到你的实现中。
注意:如果你正在使用一个定制的,然后确保添加参数到你自己定制的类的注解。这会被用于内部实例化。
2.5&支持的数据库
ORMLite支持下面的数据库。这些数据库中的某些数据库有具体需要遵守的文档。(下面给出支持的数据库,具体文档参见官方文档)
支持的数据库
Android&SQLite
Microsoft&SQL&Server
这样你有一个注解对象被持久化,添加一个无参构造器,创建你的并且定义你的类。你已经开始持久化和查询你的数据库对象了。你需要下载并且添加文件到你的中,如果你想让这个示例跑起来的话。下面是整合的代码:
// 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();
2.7&表和创建
有几个提供的工具,可以帮助你为存入数据库的类创建表和。
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这个类虽然是为使用框架设计的,但是在其他的配置方面是很有用的。它配置和被程序使用的列表。
如果系统属性设置成值,他会自动创建和这些相关的表。如果系统属性设置成值,它也会自动删除创建的表。这在测试的时候特别有用:你开始使用取得最新的测试数据库,但是实际生产过程中你需要手动改变一个具体的。你可以在你运行测试脚本的时候设置系统属性,但是在运行实际脚本时要关闭它。
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&唯一标识符字段
数据库中的记录通过定义为唯一的特殊字段成为唯一标识。记录不是必须有唯一标识字段当时很多操作(更新、删除、刷新)都需要一个唯一标识字段。这个标识要么用户提供要么数据库自动生成。标识字段有表中唯一的值并且如果你用根据查询、删除、刷新或者更新指定行的时候他们必须存在。为了配置一个成员变量作为标识成员,你应该使用下面三个设置之一(而且必须使用一个):。
2.8.1&成员变量使用
用我们的类的示例,字符串变量被标记有。这意味着变量是这个对象的标识字段。每个存入数据库都必须有一个唯一的变量值,比如你不能有两行的都是“”。
public class Account {
@DatabaseField(id = true)
当你使用利用具体的值查询时,你将使用标识成员定位数据库中
Account account = accountDao.queryForId(&John Smith&);
if (account == null) {
// the name &John Smith& does not match any rows
&注意:如果你需要改变对象字段的值,那么你必须使用方法,它获得当前对象的旧值和新值。
2.8.2&成员变量使用
你可以配置一个或的变量作为生成的标识字段。每条记录的号都是数据库自动生成的。
public class Order {
@DatabaseField(generatedId = true)
private int
传递一个对象去创建和存储到数据库时,数据库返回一个生成的值并且设置给对象。在大部分数据库类型中向表中插入一条新记录时生成的值从开始,每次增长。
// 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
在上面的代码示例中,一个构造用和两个属性。当把它传给的方法时,变量没有设置。它保存到数据库之后,会把生成的设置给变量并且()方法在方法返回后被调用是有有效的。
注意:其他特殊变量类型也是可以生成的,比如。你可以使用变量进行设置,允许向表中插入拥有已经设置过或没有设置过的对象。根据数据库类型,你可能不能改变自动生成字段的值。
2.8.3&成员变量使用
一些数据库使用一种被称为序列号生成器的东西来提供生成的值。如果你把用在这些数据库上,序列名将会被自动生成。如果这样,你需要设置序列名来匹配已经存在的,你可以使用序列名的值。
public class Order {
@DatabaseField(generatedIdSequence = &order_id_seq&)
private int
在上面的示例中,虽然值再次自动生成,但是仍然使用序列名:。如果你使用的数据库不支持序列,那么这将会抛出一个异常。
注意:根据数据库类型,你不能改变自动生成字段的值。
2.9&DAO&的使用
下面通过使用方法简单完成数据库操作:
①创建并且持久化对象到数据库。
插入一条和对象相关的记录到数据库中。
Account account = new Account();
account.name = &Jim Coakley&;
accountDao.create(account);
②查询它的字段
如果对象有个成员变量通过注解定义的,我们可以通过它的在数据库中查找一个对象。
Account account = accountDao.queryForId(name);
if (account == null) {
account not found handling ...
③更新与对象相关的数据库记录
如果你在内存中改变一个对象的成员变量,你必须调用把它持久化到数据库。这需要一个字段。
account.password = &_secret&;
accountDao.update(account);
④当数据库有改变,刷新对象
如果一些与内存中对象相关的数据库实体发生了改变,你就需要刷新来得到最新的存储对象。这需要一个字段。
accountDao.refresh(account);
⑤从数据库中删除数据
从数据库删除与对象关联的记录。一旦对象从数据库删除,你可以继续使用内存中的对象但是任何的更新或者刷新都很可能失败。这需要一个字段。
accountDao.delete(account);
⑥遍历表中所有记录
DAO也有迭代器,所以你可以简单的执行数据库中所有的记录。
// page through all of the accounts in the database
for (Account account : accountDao) {
System.out.println(account.getName());
&注意:你必须遍历迭代器所有的条目来关闭底层的对象。如果你没有通过循环走所有的途径,那么不知道关闭底层对象,并且一个到数据库的连接可能泄露,如果更迟一些垃圾回收器才获得它,那么它将被迫关闭,这会在你的代码中产出漏洞。使用下面的模板包住迭代器。
例如,下面是一个不好的循环模板。
for (Account account : accountDao) {
if (account.getName().equals(&Bob Smith&)) {
// you can't return, break, or throw from here
&如果一个异常仍出循环这种照样会发生,所以如果这样的话循环就不应该被使用。这也是一个用迟加载收集的一个案例。
⑦直接使用迭代器
你也可以直接使用迭代器,因为用循环并不是最佳选择。这种方式允许你使用更好的模板。
CloseableIterator&Account& iterator =
accountDao.closeableIterator();
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();
你也可以使用,它允许你在中使用而一直使用循环。
CloseableWrappedIterable&Account& wrappedIterable =
accountDao.getWrappedIterable();
for (Account account : wrappedIterable) {
} finally {
wrappedIterable.close();
2.10&索引成员
在你的数据类中提供了一些多种成员索引有限的支持。首先,它重点指明任何已经被标记成的成员变量已经被编入索引。一个成员变量不需要添加额外构建的索引并且如果他们被指定的话那么数据库会产生错误。
添加一个索引到没有的成员变量,你需要添加布尔域到注解。这将会在表被创建时创建一个非唯一的索引给成员变量并且如果表被删除那么将删除索引。索引用于帮助优化查询并且在查询媒介中数据量大的表时显著优化了查询时间。
public class Account {
@DatabaseField(id = true)
// this indexes the city field so queries on city
// will go faster for large tables
@DatabaseField(index = true)
这个例子在表中创建一个索引。如果你想用不同的名字,你可以使用,用允许你指定的索引名来替换othername成员。
@DatabaseField(indexName = &account_citystate_idx&)
@DatabaseField(indexName = &account_citystate_idx&)
这个示例会为和成员变量都创建一个索引。注意,通过本身查询是没有优化的,只有在和多关键字查询时才会被优化。有些数据库,它可能更好的创建一个单一字段索引在每个字段上而且如果你用和多关键字查询时它会让数据库同时使用两个索引。对于另一些数据库,推荐在多个成员变量上创建一个索引。你可能需要尝试使用命令来查明你的数据库是怎么使用你的索引的。
创建一个唯一的索引,和成员变量仅仅在注解中有效。这些操作和上面的设置一样但是将会不用创建唯一索引来确保没有任何两条记录的索引有相同的值。
2.11&发出原生语句
在大量实例中,使用定义的功能操作数据库可能还不够。由于这个原因,允许你发出查找、更新、执行等数据库原生语句给数据库。
2.11.1&发出原生查找
通过接口的内置方法并且类没有提供操作所有查询类型的能力。比如,聚合查询(sum,count,avg等等)不能当做一个对象进行操作,因为每个查询有不同的结果列表。为了这样的查询操作,你可以使用中的方法发出原生的数据库查询。这些方法返回一个对象,它表示一个结果是一个字符串数组,对象数组或者用户映射对象。查看关于的文档有更多如何使用它的详解说明,或者看看下面的示例。
// find out how many orders account-id #10 has
GenericRawResults&String[]& rawResults =
orderDao.queryRaw(
&select count(*) from orders where account_id = 10&);
// there should be 1 result
List&String[]& results = rawResults.getResults();
// the results array should have 1 value
String[] resultArray = results.get(0);
// this should print the number of orders that have this account-id
System.out.println(&Account-id 10 has & + resultArray[0] + & orders&);
你甚至可以使用构建原生的查询,如果你喜欢使用方法的话。
QueryBuilder&Account, Integer& qb = accountDao.queryBuilder();
qb.where().ge(&orderCount&, 10);
results = accountDao.queryRaw(qb.prepareStatementString());
如果你想以参数的形式使用原生查询,那么你应该像这样的:
QueryBuilder&Account, Integer& qb = accountDao.queryBuilder();
// we specify a SelectArg here to generate a ? in statement string below
qb.where().ge(&orderCount&, new SelectArg());
// the 10 at the end is an optional argument to fulfill SelectArg above
results = accountDao.queryRaw(qb.prepareStatementString(), 10);
如果你想以聚合的方式使用或者是其他原生、自定义的参数那么像下面这样做。因为只有一个结果输出你可以使用方法:
QueryBuilder&Account, Integer& qb = accountDao.queryBuilder();
// select 2 aggregate functions as the return
qb.selectRaw(&MIN(orderCount)&, &MAX(orderCount)&);
// the results will contain 2 string values for the min and max
results = accountDao.queryRaw(qb.prepareStatementString());
String[] values = results.getFirstResult();
对于有大量的结果集,你可以考虑使用利用数据库分页的对象的方法。示例:
// return the orders with the sum of their amounts per account
GenericRawResults&String[]& rawResults =
orderDao.queryRaw(
&select account_id,sum(amount) from orders group by account_id&);
// page through the results
for (String[] resultArray : rawResults) {
System.out.println(&Account-id & + resultArray[0] + & has &
+ resultArray[1] + & total orders&);
rawResults.close();
如果你传进去的结果字段类型有些字段不能合适的映射到字符串,你也可以以形式返回字段。例如:
// return the orders with the sum of their amounts per account
GenericRawResults&Object[]& rawResults =
orderDao.queryRaw(
&select account_id,sum(amount) from orders group by account_id&,
new DataType[] { DataType.LONG, DataType.INTEGER });
// page through the results
for (Object[] resultArray : rawResults) {
System.out.println(&Account-id & + resultArray[0] + & has &
+ resultArray[1] + & total orders&);
rawResults.close();
注意:能返回在不同的表中的字段,这依赖于数据库类型。
为了保证数组数据类型和返回的列匹配,你必须具体地指定字段并且不能用中的&。
你也可以通过在对象传一个你自己的对象来映射结果集。这将调用对象和一个字符串数组的映射并且它把字符串转化为对象。例如:
// return the orders with the sum of their amounts per account
GenericRawResults&Foo& rawResults =
orderDao.queryRaw(
&select account_id,sum(amount) from orders group by account_id&,
new RawRowMapper&Foo&() {
public Foo mapRow(String[] columnNames,
String[] resultColumns) {
return new Foo(Long.parseLong(resultColumns[0]),
Integer.parseInt(resultColumns[1]));
// page through the results
for (Foo foo : rawResults) {
System.out.println(&Account-id & + foo.accountId + & has &
+ foo.totalOrders + & total orders&);
rawResults.close();
注意:查询和结果字符串可以是非常具体的数据库类型。比如:
1、某一数据库需要一些字段名指定成大写,另一些需要指定成小写。
2、你必须引用你的字段名或表明,如果他们是关键字的话。
3、结果集字段名也可以是大写或者是小写。
4、Select&*&可以根据数据库类型返回表中不同的字段。
注意:就像其他的迭代器,你将需要确定循环遍历所以结果集后有自动关闭的申明。你也可以调用方法来确保迭代器和其他相关数据库连接被关闭。
2.11.2&发出原生更新语句
如果给你的功能不够灵活的话,你也可以发出数据的原生更新语句。更新的语句必须包含关键字、、&。例如:
fooDao.updateRaw(&INSERT INTO accountlog (account_id, total) &
+ &VALUES ((SELECT account_id,sum(amount) FROM accounts))
2.11.3&发出原生的执行语句
如果给你的功能不够灵活的话,你也可以发出数据的原生更新语句。例如:
fooDao.executeRaw(&ALTER TABLE accountlog DROP COLUMN partner&);
2.12&外部对象字段
ORMLite支持对象的概念,一个或多个与对象相关的字段被持久化到同一数据库的另一张表中。比如,如果在你的数据库中有一个对象,&并且每个有一个对应的对象,那么这个对象就会有外部字段。有一个外部对象,只有中的字段被持久化到表中的列。例如,这个类可以像这样:
@DatabaseTable(tableName = &orders&)
public class Order {
@DatabaseField(generatedId = true)
private int
@DatabaseField(canBeNull = false, foreign = true)
当表被创建时,有些像下面的将会被生产:
CREATE TABLE `orders`
(`id` INTEGER AUTO_INCREMENT , `account_id` INTEGER,
PRIMARY KEY (`id`));
注意:字段名不是,而是。如果你查询的时候你将会使用这个字段名。你可以在注解中使用成员来设置字段名。
当你用外部对象创建一个字段时,请注意这个外键对象不会为你自动创建。如果你的外部对象有一个数据库提供的,那么你需要在你创建其他引用它的对象之前创建它。例如:
Account account = new Account(&Jim Coakley&);
accountDao.create(account);
// this will create the account object and set any generated ids
// now we can set the account on the order and create it
Order order = new Order(&Jim Sanders&, 12.34);
order.setAccount(account);
orderDao.create(order);
如果你希望一些自动创建的等级,那么你可以使用进行设置。
当你查询一个表时,你将会得到一个对象,这对象拥有一个有它集合的字段。在外部对象中剩下的字段将有默认值(,,等)。如果你想使用中的其他字段,你必须调用类的来得到填充了的对象。比如:
Order order = orderDao.queryForId(orderId);
System.out.println(&Account-id on the order should be set: & +
order.account.id);
// this should print null for order.account.name
System.out.println(&But other fields on the account should not be set: &
+ order.account.name);
// so we refresh the account using the AccountDao
accountDao.refresh(order.getAccount());
System.out.println(&Now the account fields will be set: & +
order.account.name);
你可以通过使用设置拥有一个自动刷新的外部对象。
注意:因为我们使用,所以外部对象需要有一个字段。
你可以用两三种不同的方式查询外部字段。下面实例演示代码,代码是查询所有匹配确定的字段的所有。因为字段是字段,所有你可以通过的字段来进行查询。
// query for all orders that match a certain account
List&Order& results =
orderDao.queryBuilder().where().
eq(&account_id&, account.getName()).query();
或者你可以仅仅让从取得字段。这将演示一个和上面等同的查询:
// ORMLite will extract and use the id field internally
List&Order& results =
orderDao.queryBuilder().where().
eq(&account_id&, account).query();
2.13&外部集合
在本手册前面章节中我们有个类的例子,它有一个到表的外部对象字段。一个外部集合允许你添加表中的集合。每当对象通过的查询或刷新返回时,表和设置在上集合规定了一个单独的查询。所有的在集合中有一个对应的和匹配的外部对象。例如:
public class Account {
@ForeignCollectionField(eager = false)
ForeignCollection&Order&
在上面的示例中,注解标记了成员变量是一个匹配的集合。成员变量的类型必须要么是要么是,没有其他的集合被支持,因为其他集合难以有更多的方法支持。注解支持下面的成员:
maxEagerLevel
columnName
orderColumnName
foreignFieldName
备注:具体成员描述参见官方文档。
记住,当你有个成员变量,集合中的类必须得有一个外部成员。如果有个的外部集合,那么必须有一个外部成员。它是这么要求的,所以能找到匹配具体的。
警告:用集合甚至是()方法导致迭代器跨越数据库。你可能最想只使用集合中的和方法。
注意:就像使用方法类似,迭代器被集合返回,当你用了它那么必须关闭它,因为有链接在数据库底层一直开着。下面的方式关闭操作会执行:那么是你通过迭代器把所有的方式走一遍,那么是你调用()方法。只有会返回一个可以关闭的迭代器。这意味着循环懒加载集合是不好的模式。
在这种情况下外部集合支持add()和remove()方法:如果一个集合想对象被添加和从内部列表删除,并且被调用用来影响表以及和集合。
注意:当你在一个使用了外部集合的对象上调用时,保存在集合中的对象不是自动写到数据库的。可惜在中没有方法可以检测到对象被更新了。如果你更新一个集合中的对象你需要在上调用方法来确保对象被持久化。例如:
for (Order order : account.orders()) {
// if we are changing some field in the order
order.setAmount(123);
// then we need to update it in the database
account.orders.update(order);
2.14&DAO激活对象
另一种模式是:有对象执行和他们自己相关的数据库操作来代替使用。比如,给一个数据对象,你会调用foo.refresh()来代替fooDao.refresh(foo)。默认的模式是使用类,它允许你的数据类有他们自己的层次并且它独立于中的数据库代码。但是,如果你喜欢这种模式的话你可以自由使用类。
要使所有的类能够刷新(更新、删除等等)他们自己,那么需要继承类。例如:
@DatabaseTable(tableName = &accounts&)
public class Account extends BaseDaoEnabled {
@DatabaseField(id = true)
@DatabaseField(canBeNull = false)
首先创建对象,你需要使用对象或者你需要设置相关对象的以便它能自我创建:
account.setDao(accountDao);
account.create();
不过,任何时候一个对象被作为一个查询结果返回,那么已经被设置在继承类的对象上了。
Account account = accountDao.queryForId(name);
account.setPassword(newPassword);
account.update();
这也将会为外部成员工作。
Order order = orderDao.queryForId(orderId);
// load all of the fields from the account
order.getAccount().refresh();
这个文档有最新的操作列表,现在类仅仅可以做:
创建对象,你需要使用或者在对象上调用()。
当数据库中数据发生更新时刷新对象。
你改变了内存中的对象之后把它更新到数据库。
如果你需要更新对象的那么你需要使用这个方法。你不能改变对象的成员然后调用更新方法,因为这样对象会找不到。
从数据库删除。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:766823次
积分:5655
积分:5655
排名:第4411名
原创:18篇
转载:204篇
评论:89条
(1)(1)(1)(1)(2)(1)(1)(2)(2)(5)(7)(1)(1)(5)(6)(19)(8)(4)(4)(4)(7)(2)(3)(6)(13)(5)(5)(7)(19)(52)(17)(13)}

我要回帖

更多关于 网速测试 电信 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信