又一个使用annotation的orm的实现,非常无聊的东西。
不过实现过程中,思考了一下,感觉从select出发的orm往往是非常难用的。再简单的系统,其select语句也会出现复杂的内外连接,分组等查询逻辑。
但是在数据存储部分,也就是upate ,insert,delete部分,逻辑往往是非常简单的,使用orm会得到比较好的效果。
然后,要反思一下DAO模式,在通常理解的DAO模式中,数据的读取和写入是放在同一个DAO类当中的,在实际开发中,select相关的findXXX方法好getXXXX方法非常多,但是update,insert,add,save等方法个数都比较少,个人认为开发DAO或者说数据访问层程序的时候,应该讲DAO分为写入DAO和读取DAO,同时可以考虑在此实现读写分离,写入一个库,读取多个库,读加缓冲池,写直接写入,利用数据库机制表同步,以提高系统的伸缩性。
而且根据@1哥的答案,写入操作本身就是一个非常慢的动作,在写入时加入反射,犹如大象身上的虱子,相对磁盘来说,反射的消耗应该可以忽略。
然后,顺便对于NutzDAO进行一下小小的批评,作为DAO中间件,有些事情做了太多,反而不太好,比如引入所谓的whereClause的条件查询,真实业务中的select的SQL非常复杂,用简单的条件封装,很难满足真实开发需要的。
要知道hibernate一开始也很好用,但是面临的需求多了,边界划分不清,代码就冗肿了,慢慢就没法用了。
下面贴一点关键代码:
insert相关类:
//////////////////////
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.kamike.db.generic;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
/**
*
* @author THiNk
* @param <T>
*/
public class GenericInsert<T> {
protected T t;
protected ArrayList<GenericColumn> columns;
protected HashMap<String, Object> data;
protected ArrayList<Field> fields;
protected String tableName;
public GenericInsert(T t) {
this.t = t;
tableName = t.getClass().getAnnotation(TableName.class).value();
Field[] fs = t.getClass().getDeclaredFields();
columns = new ArrayList<>();
for (Field field : fs) {
FieldName fieldName = field.getAnnotation(FieldName.class);
if (fieldName != null) {
String fname;
if ("".equals(fieldName.value())) {
fname = field.getName();
} else {
fname = fieldName.value();
}
GenericColumn col = new GenericColumn();
col.setName(fname);
col.setField(field);
if (field.getType() == int.class) {
col.setType(GenericType.Int);
col.setIntValue(GenericReflect.getInt(field, t));
columns.add(col);
} else if (field.getType() == int.class) {
col.setType(GenericType.Double);
col.setDoubleValue(GenericReflect.getDouble(field, t));
columns.add(col);
} else if (field.getType() == String.class) {
col.setType(GenericType.String);
col.setStrValue(GenericReflect.getString(field, t));
columns.add(col);
} else if (field.getType() == long.class) {
col.setType(GenericType.Long);
col.setLongValue(GenericReflect.getLong(field, t));
columns.add(col);
} else if (field.getType() == Date.class) {
col.setType(GenericType.Timestamp);
col.setTimestampValue(new Timestamp(GenericReflect.getDate(field, t).getTime()));
columns.add(col);
} else if (field.getType() == boolean.class) {
col.setType(GenericType.Boolean);
col.setBooleanValue(GenericReflect.getBoolean(field, t));
columns.add(col);
}
}
}
}
public String sql() {
StringBuffer buffer = new StringBuffer();
buffer.append("insert into ");
buffer.append(tableName);
buffer.append("( ");
StringBuffer values = new StringBuffer();
for (Iterator<GenericColumn> it = columns.iterator(); it.hasNext();) {
GenericColumn column = it.next();
buffer.append(column.getName());
values.append("?");
if (it.hasNext()) {
buffer.append(",");
values.append(",");
}
}
buffer.append(")");
buffer.append(" values(");
buffer.append(values);
buffer.append(") ");
return buffer.toString();
}
public int bind(PreparedStatement ps) throws SQLException {
if (ps == null) {
return 0;
}
int i = 1;
for (Iterator<GenericColumn> it = columns.iterator(); it.hasNext();) {
GenericColumn column = it.next();
switch (column.getType()) {
case Int:
ps.setInt(i, column.getIntValue());
break;
case Long:
ps.setLong(i, column.getLongValue());
break;
case Double:
ps.setDouble(i, column.getDoubleValue());
break;
case Boolean:
ps.setBoolean(i, column.getBooleanValue());
break;
case Timestamp:
ps.setTimestamp(i, column.getTimestampValue());
break;
case String:
ps.setString(i, column.getStrValue());
break;
}
i++;
}
return i;
}
}
反射工具类:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.kamike.db.generic;
import java.lang.reflect.Field;
import java.util.Date;
/**
*
* @author THiNk
*/
public class GenericReflect {
public static Object get(Field field, Object obj) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return null == obj ? null : field.get(obj);
} catch (Exception e) {
return null;
}
}
public static String getString(Field field, Object obj) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return null == obj ? null : (String) field.get(obj);
} catch (Exception e) {
return null;
}
}
public static int getInt(Field field, Object obj) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return null == obj ? null : (int) field.get(obj);
} catch (Exception e) {
return 0;
}
}
public static double getDouble(Field field, Object obj) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return null == obj ? null : (double) field.get(obj);
} catch (Exception e) {
return 0d;
}
}
public static long getLong(Field field, Object obj) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return null == obj ? null : (long) field.get(obj);
} catch (Exception e) {
return 0l;
}
}
public static Date getDate(Field field, Object obj) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return null == obj ? null : (Date) field.get(obj);
} catch (Exception e) {
return new Date(System.currentTimeMillis());
}
}
public static boolean getBoolean(Field field, Object obj) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
return null == obj ? null : (boolean) field.get(obj);
} catch (Exception e) {
return false;
}
}
public static void set(Object obj, Field field, String value) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(obj, value);
} catch (Exception e) {
}
}
public static void set(Object obj, Field field, int value) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(obj, value);
} catch (Exception e) {
}
}
public static void set(Object obj, Field field, boolean value) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(obj, value);
} catch (Exception e) {
}
}
public static void set(Object obj, Field field, Date value) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(obj, value);
} catch (Exception e) {
}
}
public static void set(Object obj, Field field, long value) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(obj, value);
} catch (Exception e) {
}
}
public static void set(Object obj, Field field, double value) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(obj, value);
} catch (Exception e) {
}
}
}
表格的列处理的实体对象
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.kamike.db.generic;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.util.Date;
/**
*
* @author THiNk
*/
public class GenericColumn {
private String name;
private GenericType type;
private Field field;
private Object value;
private String strValue;
private int intValue;
private double doubleValue;
private Timestamp timestampValue;
private long longValue;
private boolean booleanValue;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the type
*/
public GenericType getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(GenericType type) {
this.type = type;
}
/**
* @return the field
*/
public Field getField() {
return field;
}
/**
* @param field the field to set
*/
public void setField(Field field) {
this.field = field;
}
/**
* @return the value
*/
public Object getValue() {
return value;
}
/**
* @param value the value to set
*/
public void setValue(Object value) {
this.value = value;
}
/**
* @return the strValue
*/
public String getStrValue() {
return strValue;
}
/**
* @param strValue the strValue to set
*/
public void setStrValue(String strValue) {
this.strValue = strValue;
}
/**
* @return the intValue
*/
public int getIntValue() {
return intValue;
}
/**
* @param intValue the intValue to set
*/
public void setIntValue(int intValue) {
this.intValue = intValue;
}
/**
* @return the doubleValue
*/
public double getDoubleValue() {
return doubleValue;
}
/**
* @param doubleValue the doubleValue to set
*/
public void setDoubleValue(double doubleValue) {
this.doubleValue = doubleValue;
}
/**
* @return the timestampValue
*/
public Timestamp getTimestampValue() {
return timestampValue;
}
/**
* @param timestampValue the timestampValue to set
*/
public void setTimestampValue(Timestamp timestampValue) {
this.timestampValue = timestampValue;
}
/**
* @return the longValue
*/
public long getLongValue() {
return longValue;
}
/**
* @param longValue the longValue to set
*/
public void setLongValue(long longValue) {
this.longValue = longValue;
}
/**
* @return the booleanValue
*/
public boolean getBooleanValue() {
return booleanValue;
}
/**
* @param booleanValue the booleanValue to set
*/
public void setBooleanValue(boolean booleanValue) {
this.booleanValue = booleanValue;
}
}
支持类型的枚举
package com.kamike.db.generic;
/**
*
* @author THiNk
*/
public enum GenericType {
String,
Int,
Long,
Boolean,
Double,
Timestamp
}
下面是几个annotation的定义
package com.kamike.db.generic;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author THiNk
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Documented
public @interface Id {
String value() default "id";
}
package com.kamike.db.generic;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author THiNk
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldName {
String value() default "";
}package com.kamike.db.generic;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
String value() default "";
}
下面贴一下,修改和删除的实现类:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.kamike.db.generic;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
/**
*
* @author THiNk
* @param <T>
*/
public class GenericUpdate<T> {
protected T t;
protected ArrayList<GenericColumn> columns;
protected ArrayList<GenericColumn> ids;
protected String tableName;
public GenericUpdate(T t) {
this.t = t;
tableName = t.getClass().getAnnotation(TableName.class).value();
Field[] fs = t.getClass().getDeclaredFields();
columns = new ArrayList<>();
for (Field field : fs) {
FieldName fieldName = field.getAnnotation(FieldName.class);
if (fieldName != null) {
String fname;
if ("".equals(fieldName.value())) {
fname = field.getName();
} else {
fname = fieldName.value();
}
GenericColumn col = new GenericColumn();
col.setName(fname);
col.setField(field);
if (field.getType() == int.class) {
col.setType(GenericType.Int);
col.setIntValue(GenericReflect.getInt(field, t));
columns.add(col);
Id id = field.getAnnotation(Id.class);
if (id != null) {
ids.add(col);
}
} else if (field.getType() == int.class) {
col.setType(GenericType.Double);
col.setDoubleValue(GenericReflect.getDouble(field, t));
columns.add(col);
Id id = field.getAnnotation(Id.class);
if (id != null) {
ids.add(col);
}
} else if (field.getType() == String.class) {
col.setType(GenericType.String);
col.setStrValue(GenericReflect.getString(field, t));
columns.add(col);
Id id = field.getAnnotation(Id.class);
if (id != null) {
ids.add(col);
}
} else if (field.getType() == long.class) {
col.setType(GenericType.Long);
col.setLongValue(GenericReflect.getLong(field, t));
columns.add(col);
Id id = field.getAnnotation(Id.class);
if (id != null) {
ids.add(col);
}
} else if (field.getType() == Date.class) {
col.setType(GenericType.Timestamp);
col.setTimestampValue(new Timestamp(GenericReflect.getDate(field, t).getTime()));
columns.add(col);
Id id = field.getAnnotation(Id.class);
if (id != null) {
ids.add(col);
}
} else if (field.getType() == boolean.class) {
col.setType(GenericType.Boolean);
col.setBooleanValue(GenericReflect.getBoolean(field, t));
columns.add(col);
Id id = field.getAnnotation(Id.class);
if (id != null) {
ids.add(col);
}
}
}
}
}
public String sql() {
StringBuffer buffer = new StringBuffer();
buffer.append("update ");
buffer.append(tableName);
buffer.append(" set ");
for (Iterator<GenericColumn> it = columns.iterator(); it.hasNext();) {
GenericColumn column = it.next();
buffer.append(column.getName());
buffer.append("=?");
if (it.hasNext()) {
buffer.append(", ");
}
}
buffer.append(" where ");
for (Iterator<GenericColumn> it = ids.iterator(); it.hasNext();) {
GenericColumn column = it.next();
buffer.append(column.getName());
buffer.append("=? ");
if (it.hasNext()) {
buffer.append(" and ");
}
}
return buffer.toString();
}
public String rawSql() {
StringBuffer buffer = new StringBuffer();
buffer.append("update ");
buffer.append(tableName);
buffer.append(" set ");
for (Iterator<GenericColumn> it = columns.iterator(); it.hasNext();) {
GenericColumn column = it.next();
buffer.append(column.getName());
buffer.append("=?");
if (it.hasNext()) {
buffer.append(", ");
}
}
return buffer.toString();
}
public int bind(PreparedStatement ps) throws SQLException {
if (ps == null) {
return 0;
}
int i = 1;
for (Iterator<GenericColumn> it = columns.iterator(); it.hasNext();) {
GenericColumn column = it.next();
switch (column.getType()) {
case Int:
ps.setInt(i, column.getIntValue());
break;
case Long:
ps.setLong(i, column.getLongValue());
break;
case Double:
ps.setDouble(i, column.getDoubleValue());
break;
case Boolean:
ps.setBoolean(i, column.getBooleanValue());
break;
case Timestamp:
ps.setTimestamp(i, column.getTimestampValue());
break;
case String:
ps.setString(i, column.getStrValue());
break;
}
i++;
}
for (Iterator<GenericColumn> it = ids.iterator(); it.hasNext();) {
GenericColumn column = it.next();
switch (column.getType()) {
case Int:
ps.setInt(i, column.getIntValue());
break;
case Long:
ps.setLong(i, column.getLongValue());
break;
case Double:
ps.setDouble(i, column.getDoubleValue());
break;
case Boolean:
ps.setBoolean(i, column.getBooleanValue());
break;
case Timestamp:
ps.setTimestamp(i, column.getTimestampValue());
break;
case String:
ps.setString(i, column.getStrValue());
break;
}
i++;
}
return i;
}
public int rawBind (PreparedStatement ps) throws SQLException {
if (ps == null) {
return 0;
}
int i = 1;
for (Iterator<GenericColumn> it = columns.iterator(); it.hasNext();) {
GenericColumn column = it.next();
switch (column.getType()) {
case Int:
ps.setInt(i, column.getIntValue());
break;
case Long:
ps.setLong(i, column.getLongValue());
break;
case Double:
ps.setDouble(i, column.getDoubleValue());
break;
case Boolean:
ps.setBoolean(i, column.getBooleanValue());
break;
case Timestamp:
ps.setTimestamp(i, column.getTimestampValue());
break;
case String:
ps.setString(i, column.getStrValue());
break;
}
i++;
}
return i;
}
}
删除:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.kamike.db.generic;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
/**
*
* @author THiNk
* @param <T>
*/
public class GenericDelete<T> {
protected T t;
protected ArrayList<GenericColumn> ids;
protected String tableName;
public GenericDelete(T t) {
this.t = t;
tableName = t.getClass().getAnnotation(TableName.class).value();
Field[] fs = t.getClass().getDeclaredFields();
ids = new ArrayList<>();
for (Field field : fs) {
FieldName fieldName = field.getAnnotation(FieldName.class);
if (fieldName != null) {
String fname;
if ("".equals(fieldName.value())) {
fname = field.getName();
} else {
fname = fieldName.value();
}
GenericColumn col = new GenericColumn();
col.setName(fname);
col.setField(field);
if (field.getType() == int.class) {
col.setType(GenericType.Int);
col.setIntValue(GenericReflect.getInt(field, t));
ids.add(col);
} else if (field.getType() == int.class) {
col.setType(GenericType.Double);
col.setDoubleValue(GenericReflect.getDouble(field, t));
ids.add(col);
} else if (field.getType() == String.class) {
col.setType(GenericType.String);
col.setStrValue(GenericReflect.getString(field, t));
ids.add(col);
} else if (field.getType() == long.class) {
col.setType(GenericType.Long);
col.setLongValue(GenericReflect.getLong(field, t));
ids.add(col);
} else if (field.getType() == Date.class) {
col.setType(GenericType.Timestamp);
col.setTimestampValue(new Timestamp(GenericReflect.getDate(field, t).getTime()));
ids.add(col);
} else if (field.getType() == boolean.class) {
col.setType(GenericType.Boolean);
col.setBooleanValue(GenericReflect.getBoolean(field, t));
ids.add(col);
}
}
}
}
public String sql() {
StringBuffer buffer = new StringBuffer();
buffer.append("delete from ");
buffer.append(tableName);
buffer.append(" where ");
for (Iterator<GenericColumn> it = ids.iterator(); it.hasNext();) {
GenericColumn id = it.next();
buffer.append(id.getName());
buffer.append("=? ");
if (it.hasNext()) {
buffer.append(" and ");
}
}
return buffer.toString();
}
public int bind(PreparedStatement ps) throws SQLException {
if (ps == null) {
return 0;
}
int i = 1;
for (Iterator<GenericColumn> it = ids.iterator(); it.hasNext();) {
GenericColumn column = it.next();
switch (column.getType()) {
case Int:
ps.setInt(i, column.getIntValue());
break;
case Long:
ps.setLong(i, column.getLongValue());
break;
case Double:
ps.setDouble(i, column.getDoubleValue());
break;
case Boolean:
ps.setBoolean(i, column.getBooleanValue());
break;
case Timestamp:
ps.setTimestamp(i, column.getTimestampValue());
break;
case String:
ps.setString(i, column.getStrValue());
break;
}
i++;
}
return i;
}
}
最终的DAO实现:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.kamike.db;
import com.kamike.db.generic.GenericDelete;
import com.kamike.db.generic.GenericInsert;
import com.kamike.db.generic.GenericUpdate;
import com.kamike.kami.MySQLBucketWriter;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class GenericWriter<T> {
//Protected
protected String tableName;
protected Transaction ts;
protected GenericWriter(Transaction ts, String tableName) {
this.tableName = tableName;
this.ts= ts;
}
public boolean add(T t) {
if (ts == null) {
return false;
}
// String uuid= UUID.randomUUID().toString();
GenericInsert<T> insert = new GenericInsert<>(t);
int success = 0;
PreparedStatement ps = null;
try {
ps = ts.preparedStatement(insert.sql());
insert.bind(ps);
success = ps.executeUpdate();
} catch (Exception e) {
ts.rollback();
System.out.println(this.getClass().getName() + e.toString());
return false;
} finally {
try {
if (ps != null) {
ps.close();
ps = null;
}
} catch (SQLException ex) {
Logger.getLogger(MySQLBucketWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
return true;
}
public boolean delete(T t) {
if (ts == null) {
return false;
}
// String uuid= UUID.randomUUID().toString();
GenericDelete<T> delete = new GenericDelete<>(t);
int success = 0;
PreparedStatement ps = null;
try {
ps = ts.preparedStatement(delete.sql());
delete.bind(ps);
success = ps.executeUpdate();
} catch (Exception e) {
ts.rollback();
System.out.println(this.getClass().getName() + e.toString());
return false;
} finally {
try {
if (ps != null) {
ps.close();
ps = null;
}
} catch (SQLException ex) {
Logger.getLogger(MySQLBucketWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
return true;
}
public boolean edit(T t) {
if (ts == null) {
return false;
}
// String uuid= UUID.randomUUID().toString();
GenericUpdate<T> update = new GenericUpdate<>(t);
int success = 0;
PreparedStatement ps = null;
try {
ps = ts.preparedStatement(update.sql());
update.bind(ps);
success = ps.executeUpdate();
} catch (Exception e) {
ts.rollback();
System.out.println(this.getClass().getName() + e.toString());
return false;
} finally {
try {
if (ps != null) {
ps.close();
ps = null;
}
} catch (SQLException ex) {
Logger.getLogger(MySQLBucketWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
return true;
}
}
最后补一下Transaction的实现,这里实现方法有很多,这里给出的Transaction只是其中一种:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.kamike.db;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author THiNk
*/
public class Transaction {
protected Connection con;
protected String dbName;
protected boolean rollback;
protected int originalTransactionIsolationLevel;
public Transaction(String dbName) {
this.dbName = dbName;
}
protected void init() {
this.rollback = false;
try {
con = MultiDbInst.getInstance().getDatabase(dbName).getSingleConnection();
con.setAutoCommit(false);
} catch (SQLException ex) {
Logger.getLogger(MySQLTransaction.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected void setTransactionIsolationLevel(int transactionIsolationLevel) {
try {
if (con != null) {
DatabaseMetaData dbmt = con.getMetaData();
if (dbmt.supportsTransactions()) {
if (dbmt.supportsTransactionIsolationLevel(transactionIsolationLevel)) {
originalTransactionIsolationLevel = con.getTransactionIsolation();
con.setTransactionIsolation(transactionIsolationLevel);
}
}
}
} catch (SQLException ex) {
Logger.getLogger(MySQLTransaction.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected void resetTransactionIsolationLevel() {
try {
if (con != null) {
DatabaseMetaData dbmt = con.getMetaData();
if (dbmt.supportsTransactions()) {
if (dbmt.supportsTransactionIsolationLevel(originalTransactionIsolationLevel)) {
con.setTransactionIsolation(originalTransactionIsolationLevel);
}
}
}
} catch (SQLException ex) {
Logger.getLogger(MySQLTransaction.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void save() {
try {
if (this.rollback) {
con.rollback();
} else {
con.commit();
}
} catch (SQLException ex) {
Logger.getLogger(MySQLTransaction.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (con != null) {
con.setAutoCommit(true);
con.close();
con = null;
}
} catch (SQLException ex) {
Logger.getLogger(MySQLTransaction.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* 如果忘记关闭连接池,那么对象自动销毁的时候,也需要归还链接
*/
public void finalize() {
try {
if (con != null) {
con.close();
con = null;
}
} catch (SQLException ex) {
Logger.getLogger(MySQLTransaction.class.getName()).log(Level.SEVERE, null, ex);
}
try {
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(MySQLTransaction.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* @return the ps
*/
public PreparedStatement preparedStatement(String sql) throws SQLException {
return con.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
}
/**
* @param rollback the rollback to set
*/
public void rollback() {
this.rollback = true;
}
}
最后,再次感谢@1哥
来源:oschina
链接:https://my.oschina.net/u/1378360/blog/194985