关于jdbc连接数据库的步骤以及注意点

本文介绍了一种使用JDBC从旧数据库同步数据到新数据库的方法。通过反射机制动态执行SQL语句并管理数据库连接,确保数据迁移过程中的事务完整性和安全性。


最近项目上线,要从老数据库中同步数据到新库中,用到了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();
			}
		}
	}
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值