Android进阶之强大的批处理功能
2012-07-26 16:05
204 查看
博客出自:http://blog.csdn.net/liuxian13183,转载注明出处! All Rights Reserved !
批量处理可以节省时间,不必每次打开数据进行dao操作,功能强大,效率高效
1、Android中的批量处理
sqlDb.beginTransaction();// 批量处理的开始
for (int i = 0; i < list.size(); i++) {
dbHelper.insertGroup(list.get(i), sqlDb);
}
sqlDb.setTransactionSuccessful();// 表示成功插入,必不可少
sqlDb.endTransaction();
sqlDb.close();
2、获取联系人信息
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(Contacts.CONTENT_URI, null, null, null, null);
while (cursor.moveToNext()) {
// 取得联系人的ID索引值
String contactId = cursor.getString(cursor
.getColumnIndex(Contacts._ID));
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
// 取得联系人名字
ContentProviderOperation operation = ContentProviderOperation
.newAssertQuery(Contacts.CONTENT_URI).withExpectedCount(1)
.withValueBackReference(PhoneLookup.DISPLAY_NAME, 0)
.build();
operations.add(operation);
// 取得私人号码
operation = ContentProviderOperation
.newAssertQuery(Phone.CONTENT_URI)
.withSelection(Phone.CONTACT_ID + "=?",
new String[] { contactId + "" })
.withValueBackReference(Phone.NUMBER, 0).build();
operations.add(operation);
ContentResolver resolver = context.getContentResolver();
// 批量执行,返回执行结果集
ContentProviderResult[] results = null;
try {
results = resolver.applyBatch("com.android.contacts",
operations);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3、其他,在处理数据库数据交互方面也会用到Statement和PreparedStatement JDBC API来批量插入数据。
此外,我们将努力探索一些场景,如在内存不足时正常运行,以及如何优化批量操作。
首先,使用Java JDBC基本的API批量插入数据到数据库中。
Simple Batch - 简单批处理
我把它叫做简单批处理。要求很简单,执行批量插入列表,而不是为每个INSERT语句每次提交数据库,我们将使用JDBC批处理操作和优化性能。
想想一下下面的代码:
Bad Code
String [] queries = {
"insert into employee (name, city, phone) values ('A', 'X', '123')",
"insert into employee (name, city, phone) values ('B', 'Y', '234')",
"insert into employee (name, city, phone) values ('C', 'Z', '345')",
};
Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (String query : queries) {
statemenet.execute(query);
}
statemenet.close();
connection.close();
这是糟糕的代码。它单独执行每个查询,每个INSERT语句的都提交一次数据库。考虑一下,如果你要插入1000条记录呢?这是不是一个好主意。
下面是执行批量插入的基本代码。来看看:
Good Code
Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (String query : queries) {
statemenet.addBatch(query);
}
statemenet.executeBatch();
statemenet.close();
connection.close();
请注意我们如何使用addBatch()方法,而不是直接执行查询。然后,加入所有的查询,我们使用statement.executeBatch()方法一次执行他们。没有什么花哨,只是一个简单的批量插入。
请注意,我们已经从一个String数组构建了查询。现在,你可能会想,使其动态化。例如:
import java.sql.Connection;
import java.sql.Statement;
//...
Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (Employee employee: employees) {
String query = "insert into employee (name, city) values('"
+ employee.getName() + "','" + employee.getCity + "')";
statemenet.addBatch(query);
}
statemenet.executeBatch();
statemenet.close();
connection.close();
请注意我们是如何从Employee对象中的数据动态创建查询并在批处理中添加,插入一气呵成。完美!是不是?
等等......你必须思考什么关于SQL注入?这样动态创建的查询SQL注入是很容易的。并且每个插入查询每次都被编译。
为什么不使用PreparedStatement而不是简单的声明。是的,这是个解决方案。下面是SQL注入安全批处理。
SQL Injection Safe Batch - SQL注入安全批处理
思考一下下面代码:
import java.sql.Connection;
import java.sql.PreparedStatement;
//...
String sql = "insert into employee (name, city, phone) values (?, ?, ?)";
Connection connection = new getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
for (Employee employee: employees) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getCity());
ps.setString(3, employee.getPhone());
ps.addBatch();
}
ps.executeBatch();
ps.close();
connection.close();
看看上面的代码。漂亮。我们使用的java.sql.PreparedStatement和在批处理中添加INSERT查询。这是你必须实现批量插入逻辑的解决方案,而不是上述Statement那个。
这一解决方案仍然存在一个问题。考虑这样一个场景,在您想要插入到数据库使用批处理上万条记录。嗯,可能产生的OutOfMemoryError:
java.lang.OutOfMemoryError: Java heap space
com.mysql.jdbc.ServerPreparedStatement$BatchedBindValues.<init>(ServerPreparedStatement.java:72)
com.mysql.jdbc.ServerPreparedStatement.addBatch(ServerPreparedStatement.java:330)
org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:171)
这是因为你试图在一个批次添加所有语句,并一次插入。最好的办法是将执行分批次。看看下面的解决方案
Smart Insert: Batch within Batch - 智能插入:将整批分批
这是一个简单的解决方案。考虑批量大小为1000,每1000个查询语句为一批插入提交。
String sql = "insert into employee (name, city, phone) values (?, ?, ?)";
Connection connection = new getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
final int batchSize = 1000;
int count = 0;
for (Employee employee: employees) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getCity());
ps.setString(3, employee.getPhone());
ps.addBatch();
if(++count % batchSize == 0) {
ps.executeBatch();
}
}
ps.executeBatch(); // insert remaining records
ps.close();
connection.close();
这才是理想的解决方案,它避免了SQL注入和内存不足的问题。看看我们如何递增计数器计数,一旦BATCHSIZE 达到 1000,我们调用executeBatch()提交。
批量处理可以节省时间,不必每次打开数据进行dao操作,功能强大,效率高效
1、Android中的批量处理
sqlDb.beginTransaction();// 批量处理的开始
for (int i = 0; i < list.size(); i++) {
dbHelper.insertGroup(list.get(i), sqlDb);
}
sqlDb.setTransactionSuccessful();// 表示成功插入,必不可少
sqlDb.endTransaction();
sqlDb.close();
2、获取联系人信息
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(Contacts.CONTENT_URI, null, null, null, null);
while (cursor.moveToNext()) {
// 取得联系人的ID索引值
String contactId = cursor.getString(cursor
.getColumnIndex(Contacts._ID));
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
// 取得联系人名字
ContentProviderOperation operation = ContentProviderOperation
.newAssertQuery(Contacts.CONTENT_URI).withExpectedCount(1)
.withValueBackReference(PhoneLookup.DISPLAY_NAME, 0)
.build();
operations.add(operation);
// 取得私人号码
operation = ContentProviderOperation
.newAssertQuery(Phone.CONTENT_URI)
.withSelection(Phone.CONTACT_ID + "=?",
new String[] { contactId + "" })
.withValueBackReference(Phone.NUMBER, 0).build();
operations.add(operation);
ContentResolver resolver = context.getContentResolver();
// 批量执行,返回执行结果集
ContentProviderResult[] results = null;
try {
results = resolver.applyBatch("com.android.contacts",
operations);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3、其他,在处理数据库数据交互方面也会用到Statement和PreparedStatement JDBC API来批量插入数据。
此外,我们将努力探索一些场景,如在内存不足时正常运行,以及如何优化批量操作。
首先,使用Java JDBC基本的API批量插入数据到数据库中。
Simple Batch - 简单批处理
我把它叫做简单批处理。要求很简单,执行批量插入列表,而不是为每个INSERT语句每次提交数据库,我们将使用JDBC批处理操作和优化性能。
想想一下下面的代码:
Bad Code
String [] queries = {
"insert into employee (name, city, phone) values ('A', 'X', '123')",
"insert into employee (name, city, phone) values ('B', 'Y', '234')",
"insert into employee (name, city, phone) values ('C', 'Z', '345')",
};
Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (String query : queries) {
statemenet.execute(query);
}
statemenet.close();
connection.close();
这是糟糕的代码。它单独执行每个查询,每个INSERT语句的都提交一次数据库。考虑一下,如果你要插入1000条记录呢?这是不是一个好主意。
下面是执行批量插入的基本代码。来看看:
Good Code
Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (String query : queries) {
statemenet.addBatch(query);
}
statemenet.executeBatch();
statemenet.close();
connection.close();
请注意我们如何使用addBatch()方法,而不是直接执行查询。然后,加入所有的查询,我们使用statement.executeBatch()方法一次执行他们。没有什么花哨,只是一个简单的批量插入。
请注意,我们已经从一个String数组构建了查询。现在,你可能会想,使其动态化。例如:
import java.sql.Connection;
import java.sql.Statement;
//...
Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (Employee employee: employees) {
String query = "insert into employee (name, city) values('"
+ employee.getName() + "','" + employee.getCity + "')";
statemenet.addBatch(query);
}
statemenet.executeBatch();
statemenet.close();
connection.close();
请注意我们是如何从Employee对象中的数据动态创建查询并在批处理中添加,插入一气呵成。完美!是不是?
等等......你必须思考什么关于SQL注入?这样动态创建的查询SQL注入是很容易的。并且每个插入查询每次都被编译。
为什么不使用PreparedStatement而不是简单的声明。是的,这是个解决方案。下面是SQL注入安全批处理。
SQL Injection Safe Batch - SQL注入安全批处理
思考一下下面代码:
import java.sql.Connection;
import java.sql.PreparedStatement;
//...
String sql = "insert into employee (name, city, phone) values (?, ?, ?)";
Connection connection = new getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
for (Employee employee: employees) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getCity());
ps.setString(3, employee.getPhone());
ps.addBatch();
}
ps.executeBatch();
ps.close();
connection.close();
看看上面的代码。漂亮。我们使用的java.sql.PreparedStatement和在批处理中添加INSERT查询。这是你必须实现批量插入逻辑的解决方案,而不是上述Statement那个。
这一解决方案仍然存在一个问题。考虑这样一个场景,在您想要插入到数据库使用批处理上万条记录。嗯,可能产生的OutOfMemoryError:
java.lang.OutOfMemoryError: Java heap space
com.mysql.jdbc.ServerPreparedStatement$BatchedBindValues.<init>(ServerPreparedStatement.java:72)
com.mysql.jdbc.ServerPreparedStatement.addBatch(ServerPreparedStatement.java:330)
org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:171)
这是因为你试图在一个批次添加所有语句,并一次插入。最好的办法是将执行分批次。看看下面的解决方案
Smart Insert: Batch within Batch - 智能插入:将整批分批
这是一个简单的解决方案。考虑批量大小为1000,每1000个查询语句为一批插入提交。
String sql = "insert into employee (name, city, phone) values (?, ?, ?)";
Connection connection = new getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
final int batchSize = 1000;
int count = 0;
for (Employee employee: employees) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getCity());
ps.setString(3, employee.getPhone());
ps.addBatch();
if(++count % batchSize == 0) {
ps.executeBatch();
}
}
ps.executeBatch(); // insert remaining records
ps.close();
connection.close();
这才是理想的解决方案,它避免了SQL注入和内存不足的问题。看看我们如何递增计数器计数,一旦BATCHSIZE 达到 1000,我们调用executeBatch()提交。
相关文章推荐
- Android进阶之强大的批处理功能
- 强大的批处理功能
- Android: 按键的功能及处理机制
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- linux shell script 进阶篇(1)--如何打造功能强大的函数
- Android开发拍照功能横竖屏处理方法
- [学习笔记]Android系统功能之多点触摸交互处理
- Adobe终于在Android上推Photoshop Fix,功能强大的手机修图APP
- Android进阶之ListView实现多条数据同时倒计时功能
- Android View进阶之RecyclerView 实现滑动删除和拖拽功能
- Android高级进阶九 Android OpenGL对立方体进行光照处理
- Android:用Handler实现异步处理功能
- 我的Android进阶之旅------>Android实现音乐示波器、均衡器、重低音和音场功能
- Android App注销功能 的堆栈处理
- Android中Fragment的强大功能
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- 功能强大的图片截取修剪神器:Android SimpleCropView及其实例代码重用简析
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- android UI进阶之实现listview的分页加载 处理加载完毕