一、主要思路
在需要同时插入多条数据时,这其中可能是同一个表的多条记录,也可能是多个不同表之间的数据同时更新。对此,我们需要保证其中的原子性和一致性,做到要么全部操作都能全部成功完成,否则全部不操作。
我们可以通过SQL的事务来对相关数据库操作进行处理,在开始conn.setAutoCommit(false);(conn是或得的连接)把本次运行的SQL操作改为非自动运行,在配置好各SQL语句之后,调用conn.commit();来运行,其中通过try{……}catch……来捕捉异常,如果遇到错误时,就调用conn.rollback();来对本次操作进行回滚到操作前的状态,防止存在错误数据和脏数据。
二、主要实现方法
/**
* 批量插入对象-同一个表多条记录
*
* 注意:对象字段不能为数据库关键字
* @param list
* @return
* @throws SQLException
* @author lims
* @date 2015-08-28
*/
public int[] insertSameTable(List list) throws SQLException {
if (list == null || list.size() == 0) {
return null;
}
String sql = getInsertSql(list.get(0));
PreparedStatement ps = null;
String[] fields = null;
int[] result = null;
Connection conn=getConnection();
try {
ps = conn.prepareStatement(sql.toString());
this.startTransaction(conn);
for (Pojo obj : list) {
Map pojo_bean = obj.listInsertableFields();
fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()]);
for (int i = 0; i < fields.length; i++) {
ps.setObject(i + 1, pojo_bean.get(fields[i]));
}
ps.addBatch();
}
result = ps.executeBatch();
this.commitTransaction(conn);
} catch(Exception e){
conn.rollback();
throw new RuntimeException(e);
} finally {
fields = null;
org.apache.commons.dbutils.DbUtils.closeQuietly(ps);
this.closeConnection(conn);
}
return result;
}
/**
* 批量插入对象-多表插入
*
* 注意:对象字段不能为数据库关键字
* @param list
* @return
* @throws SQLException
* @author lims
* @date 2015-08-28
*/
public int insertMutilTable(List list) throws SQLException {
if (list == null || list.size() == 0) {
return 0;
}
String[] fields;
PreparedStatement ps = null;
int result = 0;
Connection conn=getConnection();
try {
this.startTransaction(conn);
for (Pojo obj : list) {
Map pojo_bean = obj.listInsertableFields();
String sql = getInsertSql(obj);
ps = conn.prepareStatement(sql.toString());
fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()]);
for (int i = 0; i < fields.length; i++) {
ps.setObject(i + 1, pojo_bean.get(fields[i]));
}
result = ps.executeUpdate();
}
this.commitTransaction(conn);
} catch(Exception e){
conn.rollback();
throw new RuntimeException(e);
} finally {
fields = null;
org.apache.commons.dbutils.DbUtils.closeQuietly(ps);
this.closeConnection(conn);
}
return result;
}
/**
* 批量更新同一个表的多条记录
* @param list
* @return
* @throws SQLException
* @author lims
* @date 2015-08-28
*/
public int[] updateSameTable(List list) throws SQLException {
if (list == null || list.size() == 0) {
return null;
}
String[] fields;
PreparedStatement ps = null;
int[] result = null;
Connection conn=getConnection();
try {
this.startTransaction(conn);
for (Pojo obj : list) {
Map pojo_bean = obj.listInsertableFields();
fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()]);
StringBuilder sql = new StringBuilder();
sql.append("update "+getTableName(obj.getClass())+" set ");
for (int i = 0; i < fields.length; i++) {
if (i > 0)
sql.append(',');
sql.append(fields[i]).append(" = ? ");
}
sql.append(" where id=?");
ps = conn.prepareStatement(sql.toString());
fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()+1]);
for (int i = 0; i < fields.length; i++) {
if(i==fields.length-1) {
ps.setObject(i + 1, obj.getId());
}
else {
ps.setObject(i + 1, pojo_bean.get(fields[i]));
}
}
ps.addBatch();
}
result = ps.executeBatch();
this.commitTransaction(conn);
} catch(Exception e){
conn.rollback();
throw new RuntimeException(e);
} finally {
ps.clearBatch();
fields = null;
org.apache.commons.dbutils.DbUtils.closeQuietly(ps);
this.closeConnection(conn);
}
return result;
}
/**
* 多表更新
* @param list
* @return
* @throws SQLException
* @author lims
* @date 2015-08-28
*/
public int updateMutilTable(List list) throws SQLException {
if (list == null || list.size() == 0) {
return 0;
}
String[] fields;
PreparedStatement ps = null;
int result = 0;
Connection conn=getConnection();
try {
this.startTransaction(conn);
for (Pojo obj : list) {
Map pojo_bean = obj.listInsertableFields();
String sql = getUpdateSql(obj);
ps = conn.prepareStatement(sql.toString());
fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()+1]);
for (int i = 0; i < fields.length; i++) {
if(i==fields.length-1) {
ps.setObject(i + 1, obj.getId());
}
else {
ps.setObject(i + 1, pojo_bean.get(fields[i]));
}
}
result = ps.executeUpdate();
}
this.commitTransaction(conn);
} catch(Exception e){
conn.rollback();
throw new RuntimeException(e);
} finally {
fields = null;
org.apache.commons.dbutils.DbUtils.closeQuietly(ps);
this.closeConnection(conn);
}
return result;
}
/**
* 插入数据和更新多表数据
* @param list
* @return
* @throws SQLException
* @author lims
* @date 2015-08-28
*/
public int insertAndUpdateMutilTable(List saveList,List updateList) throws SQLException {
if (saveList == null || saveList.size() == 0 || updateList == null || updateList.size() == 0) {
return 0;
}
String[] fields;
PreparedStatement ps = null;
int result = 0;
Connection conn=getConnection();
try {
this.startTransaction(conn);
for (Pojo obj : saveList) {//插入操作
Map pojo_bean = obj.listInsertableFields();
String sql = getInsertSql(obj);
ps = conn.prepareStatement(sql.toString());
fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()]);
for (int i = 0; i < fields.length; i++) {
ps.setObject(i + 1, pojo_bean.get(fields[i]));
}
result = ps.executeUpdate();
}
for (Pojo obj : updateList) {//更新操作
Map pojo_bean = obj.listInsertableFields();
String sql = getUpdateSql(obj);
ps = conn.prepareStatement(sql.toString());
fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()+1]);
for (int i = 0; i < fields.length; i++) {
if(i==fields.length-1) {
ps.setObject(i + 1, obj.getId());
}
else {
ps.setObject(i + 1, pojo_bean.get(fields[i]));
}
}
result = ps.executeUpdate();
}
this.commitTransaction(conn);
} catch(Exception e){
conn.rollback();
throw new RuntimeException(e);
} finally {
fields = null;
org.apache.commons.dbutils.DbUtils.closeQuietly(ps);
this.closeConnection(conn);
}
return result;
}
protected abstract Connection getConnection() throws SQLException;
protected abstract void closeConnection(Connection conn);
private void startTransaction(Connection conn) {
try {
if (conn != null) {
conn.setAutoCommit(false);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void commitTransaction(Connection conn) {
try {
if (conn != null) {
conn.commit();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取Pojo对应的数据库表名
*
* @param c
* @return
*/
private static String getTableName(Class c) {
try {
String tn = tableNameCache.get(c.getSimpleName());
if (tn == null) {
tn = c.newInstance().tableName();
tableNameCache.put(c.getSimpleName(), tn);
}
return tn;
} catch (Exception e) {
log.error("Get " + c.getSimpleName() + " name exception.");
return null;
}
}
/**
* 获取Pojo的插入sql语句
*
* @param obj
* @return
*/
private static String getInsertSql(Pojo obj) {
try {
String insertSql = insertSqlCache.get(obj.getClass().getName());
if (insertSql == null) {
Map pojo_bean = obj.listInsertableFields();
String[] fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()]);
StringBuilder sql = new StringBuilder("INSERT INTO ");
sql.append(obj.tableName());
sql.append('(');
for (int i = 0; i < fields.length; i++) {
if (i > 0)
sql.append(',');
sql.append(fields[i]);
}
sql.append(") VALUES(");
for (int i = 0; i < fields.length; i++) {
if (i > 0)
sql.append(',');
sql.append('?');
}
sql.append(')');
insertSql = sql.toString();
sql = null;
insertSqlCache.put(obj.getClass().getName(), insertSql);
}
return insertSql;
} catch (Exception e) {
log.error("Get " + obj.getClass().getSimpleName()
+ " insertSql exception.");
return null;
}
}
/**
* 获取Pojo的更新sql语句
*
* @param obj
* @return
* @author lims
* @date 2015-08-23
*/
private static String getUpdateSql(Pojo obj) {
try {
String updateSql = updateSqlCache.get(obj.getClass().getName());
if (updateSql == null) {
Map pojo_bean = obj.listInsertableFields();
String[] fields = pojo_bean.keySet().toArray(
new String[pojo_bean.size()]);
StringBuilder sql = new StringBuilder();
sql.append("update "+getTableName(obj.getClass())+" set ");
for (int i = 0; i < fields.length; i++) {
if (i > 0)
sql.append(',');
sql.append(fields[i]).append(" = ? ");
}
sql.append(" where id=?");
updateSql = sql.toString();
sql = null;
updateSqlCache.put(obj.getClass().getName(), updateSql);
}
return updateSql;
} catch (Exception e) {
log.error("Get " + obj.getClass().getSimpleName()
+ " updateSql exception.");
return null;
}
}
四、上面用到的持久化基类
import org.apache.commons.beanutils.BeanUtils;
import java.io.Serializable;
import java.util.Map;
/**
* 持久化基类
*/
public abstract class Pojo implements Serializable {
private static final long serialVersionUID = 1L;
protected int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String tableName() {
String tn=getClass().getSimpleName() ;
if(tn.endsWith("Bean")) {
tn=tn.substring(0,tn.length()-4);
}
tn = tn.toLowerCase();
return tn;
}
protected String cacheRegion() {
return this.getClass().getSimpleName();
}
/**
* 列出要插入到数据库的字段集合,子类可以按照实际需求覆盖
* @return
*/
public Map listInsertableFields() {
try {
Map props = BeanUtils.describe(this);
props.remove("id");
props.remove("class");
for(String s:props.keySet()){
if(s.endsWith("_"))props.remove(s);
}
return props;
} catch (Exception e) {
throw new RuntimeException("Exception when Fetching fields of "
+ this);
}
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
// 不同的子类尽管ID是相同也是不相等的
if (!getClass().equals(obj.getClass()))
return false;
Pojo wb = (Pojo) obj;
return wb.getId() == getId();
}
}