最近项目上线,要从老数据库中同步数据到新库中,用到了jdbc,也对此有了一部分新的了解,下面记下自己的收获。
package data.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import cn.mysteel.util.StringUtils;
public class DataBaseUtils
{
private static final String DRIVER_MYSQL = "com.mysql.jdbc.Driver";
public static final String IP_DEF = "";//target数据库IP
public static final String IP_ERP_OLD = "";//orign数据库IP
public static final String IP_TRADE_OLD = "";
public static final String DB_DEF = "";//target数据库名称
public static final String DB_ERP_OLD = "";//orign数据库名称
public static final String DB_TRADE_OLD = "";
private static final String USER_DEF = "";//用户名密码
private static final String PASSWORD_DEF = "";
public static final String USER_DEF_OLD_ERP = "";
public static final String PASSWORD_DEF_OLD_ERP = "";
public static final String USER_DEF_OLD_MALL = "";
public static final String PASSWORD_DEF_OLD_MALL = "";
// private static final String USER_NAME = "";
// private static final String PASSWORD = "";
public static void execute(Class<?> clazz, String ... args)
{
Connection conn = null;
PreparedStatement ps = null;
String methodName = (null != args && args.length > 0 && StringUtils.isNotTrimEmpty(args[0])) ? args[0] : "execute";
String sql = (null != args && args.length > 1 && StringUtils.isNotTrimEmpty(args[1])) ? args[1] : "SQL";
String ip = (null != args && args.length > 2 && StringUtils.isNotTrimEmpty(args[2])) ? args[2] : IP_DEF;
String dbName = (null != args && args.length > 3 && StringUtils.isNotTrimEmpty(args[3])) ? args[3] : DB_DEF;
String username = (null != args && args.length > 4 && StringUtils.isNotTrimEmpty(args[4])) ? args[4] : USER_DEF;
String password = (null != args && args.length > 5 && StringUtils.isNotTrimEmpty(args[5])) ? args[5] : PASSWORD_DEF;
try
{
conn = getConnection(ip, dbName, username, password);
/*
* setAutoCommit总的来说就是保持数据的完整性,一个系统的更新操作可能要涉及多张表,需多个SQL语句进行操作
* 循环里连续的进行插入操作,如果你在开始时设置了:conn.setAutoCommit(false);
* 最后才进行conn.commit(),这样你即使插入的时候报错,修改的内容也不会提交到数据库, 而如果你没有手动的进行setAutoCommit(false);
* 出错时就会造成,前几条插入,后几条没有会形成脏数据~~
*
* setAutoCommit(false)的误用:(设定setAutoCommit(false)没有在catch中进行Connection的rollBack操作,操作的表就会被锁住,造成数据库死锁):
* 误用Connection.setAutoCommit导致的数据库死锁问题。系统在发布到用户的的服务器了,运行一段时间偶尔出现某些功能不能正常运行,甚至不能自动恢复,
* 严重导致服务器当机,表现为服务器不响应用户的请求,数据库有大量的锁。在服务器重启后才能恢复正常。
*
* 写代码的人把数据库连接con 设置成非自动提交,但没有在执行出现异常的时候进行回滚。如果在执行数据库操作的时候出现异常,con既没有提交也没有回滚,
* 操作的表就会被锁住(如果oracle数据库就是行锁),而这个锁却没有机会释放。有人会质疑,在执行con.close()的时候不会释放锁吗?因为如果应用服务器使
* 用了数据库连接池,连接不会被断开。
*
* 一定不能大意哦,如果设置成非自动提交,在最后一定要调用commit或者rollback方法)
*/
conn.setAutoCommit(false);
Field field = clazz.getDeclaredField(sql); //getDeclaredField是可以获取一个类的所有字段. getField只能获取类的public 字段.
field.setAccessible(true); // java代码中,常常将一个类的成员变量置为private,在类的外面获取此类的私有成员变量的value,就必须进行此操作
ps = conn.prepareStatement(field.get(null).toString());// get(null)是因为要获取的是静态变量(static),而不是实例变量(非static),如果是实例变量 那就要传这个实例 获取这个实例的这个属性的值
Method method = clazz.getMethod(methodName, PreparedStatement.class);// 获取类的方法
method.invoke(null, ps);// 执行方法
conn.commit();
}
catch (SQLException | NoSuchMethodException | SecurityException | IllegalArgumentException
| IllegalAccessException | InvocationTargetException | NoSuchFieldException e)
{
if (conn != null)
{
try
{
conn.rollback();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
}
e.printStackTrace();
}
finally
{
close(conn, ps);
}
}
public static Connection getConnection(String ip, String dbName, String userName, String password)
{
Connection conn = null;
String url = "jdbc:mysql://" + ip + "/" + dbName + "?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true";
try
{
Class.forName(DRIVER_MYSQL);
conn = DriverManager.getConnection(url, userName, password);
}
catch (Exception e)
{
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn, PreparedStatement ps, ResultSet rs)
{
closeResultSet(rs);
closePreparedStatement(ps);
closeConnection(conn);
}
public static void close(Connection conn, PreparedStatement ps)
{
closePreparedStatement(ps);
closeConnection(conn);
}
public static void closeConnection(Connection conn)
{
if (conn != null)
{
try
{
conn.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
public static void closePreparedStatement(PreparedStatement ps)
{
if (ps != null)
{
try
{
ps.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
public static void closeResultSet(ResultSet rs)
{
if (rs != null)
{
try
{
rs.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
}