java动态原生配置数据库参数执行sql

主要步骤

1、maven依赖、实体类 略

2、在resource目录下新建jdbc.properties

# 也可以是oracle、sqlserver、hive等数据库的驱动类
jdbc.driver=com.mysql.jdbc.Driver
jdbc.datasource.size=10

jdbc.url=jdbc:mysql://localhost:3306/database
jdbc.user=root
jdbc.password=123456

3、新建config类,用于管理驱动配置

import java.io.InputStream;
import java.util.Properties;

public class ConfigurationManager {
	// 私有,外界不能直接获取property对象,以防止错误更新了jdbc.properties文件中某个key对应的value值
	private static Properties property = new Properties();
	// 采用静态代码块
	// 类第一次使用的时候,就会加载,加载的时候,就会初始化类,初始化类的时候就会执行类的静态代码块
	// 在整个JVM生命周期内,有且仅加载一次,然后以后就是重复使用,效率比较高;不用反复加载多次
	static {
		try{
			// 调用ClassLoader的getResourceAsStream()这个方法,就可以用类加载器,去加载类加载路径中的指定的文件
			InputStream in = ConfigurationManager.class.getClassLoader().getResourceAsStream("jdbc.properties"); 
			// 调用Properties的load()方法,可将文件中的符合“key=value”格式的配置项,都加载到Properties对象中
			property.load(in);			
		}catch(Exception e){
			e.printStackTrace(); 
		}
	}
	// 根据key获取属性,默认返回值都是string类型,使用时需要转化
	public static String getProperty(String key) {
		return prop.getProperty(key);
	}
}

4、常量接口也可以是枚举

public interface Constants {
	// 对应于jdbc.properties的key
	String JDBC_DRIVER = "jdbc.driver";
	String JDBC_DATASOURCE_SIZE = "jdbc.datasource.size";
	String JDBC_URL = "jdbc.url";
	String JDBC_USER = "jdbc.user";
	String JDBC_PASSWORD = "jdbc.password";
}

5、新建jdbc组件类,包括获取连接到查询结束的整个生命周期

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.LinkedList;
import java.util.List;

public class JDBCHelper {
	// 一、在静态代码块中,直接加载数据库的驱动
	// 调用ConfigurationManager的getProperty方法
	static {
        try {
            String driver = ConfigurationManager.getProperty(Constants.JDBC_DRIVER);
            Class.forName(driver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
	
	// 二、采用懒汉式单例模式
	// 因为内部要封装一个简单的内部的数据库连接池,为了保证数据库连接池有且仅有一份,所以就通过单例的方式
	// 保证JDBCHelper只有一个实例,实例中只有一份数据库连接池
	// 这里的 volatile 是为了禁止对象创建过程的指令重排序
	// 1、给对象分配内存空间;
	// 2、调用对象的构造器方法,并执行初始化操作;
	// 3、将变量指向相应的内存地址
	// 即为了防止2和3步发生排序,防止其他线程拿到一个尚未初始化完成的instance
	private static volatile JDBCHelper instance = null;

	// 简易数据库连接池,即采用单链表list来装
	private LinkedList<Connection> datasource = new LinkedList<>();
	
	// 线程安全又极大提高性能地获取单例
	public static JDBCHelper getInstance() {
		if(instance == null){
			synchronized (JDBCHelper.class){
				// 一定要再判断
				// 为了避免当两个线程都进入第一个if,然后一个线程获得了锁进入new了对象,防止释放锁后另一个线程进来new对象
				if(instance == null){
					instance = new JDBCHelper();
				}
			}
		}
		return instance;
	}
	
	// 三、创建唯一的一个数据库连接池
	// 如果没有实现逻辑也一定要写,防止默认构造方法为公有方法
	private JDBCHelper(){
		// 获取连接池大小
		int datasourceSize = Integer.valueof(ConfigurationManager.getProperty(Constants.JDBC_DATASOURCE_SIZE));
        // 然后创建指定数量的数据库连接,并放入数据库连接池中
        for (int i = 0; i < datasourceSize; i++) {
        	String url = ConfigurationManager.getProperty(Constants.JDBC_URL);
        	String user = ConfigurationManager.getProperty(Constants.JDBC_USER);
            String password = ConfigurationManager.getProperty(Constants.JDBC_PASSWORD);
            // 获取连接并压入链表中
            try {
                Connection conn = DriverManager.getConnection(url, user, password);
                datasource.push(conn);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
	}
	
	// 四、提供获取数据库连接的方法
	// 线程安全
	// 需实现一个简单的等待机制,去等待获取到数据库连接,应对连接被用光的情况
	public synchronized Connection getConnection() {
        while (datasource.size() == 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return datasource.poll();
    }

	// 五、执行sql
	// 查回调接口
	public static interface QueryCallback {
        void process(ResultSet rs) throws Exception;
    }
    // 查询
	public void executeQuery(String sql, Object[] params,
                             QueryCallback callback) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
        	// 获取连接
            conn = getConnection();
            // 开启会话
            pstmt = conn.prepareStatement(sql);
			// 传入参数
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    pstmt.setObject(i + 1, params[i]);
                }
            }
			// 执行查询
            rs = pstmt.executeQuery();
			// 结果集封装
            callback.process(rs);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
            	// 将该连接加入连接池
                datasource.push(conn);
            }
        }
    }

	// 批量查询
	public int[] executeBatch(String sql, List<Object[]> paramsList) {
        int[] rtn = null;
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            conn = getConnection();

            // 使用Connection对象,取消自动提交
            conn.setAutoCommit(false);

            pstmt = conn.prepareStatement(sql);

            // 使用PreparedStatement.addBatch()方法加入批量的SQL参数
            if (paramsList != null && paramsList.size() > 0) {
                for (Object[] params : paramsList) {
                    for (int i = 0; i < params.length; i++) {
                        pstmt.setObject(i + 1, params[i]);
                    }
                    pstmt.addBatch();
                }
            }

            // 使用PreparedStatement.executeBatch()方法,执行批量的SQL语句
            rtn = pstmt.executeBatch();

            // 最后一步:使用Connection对象,提交批量的SQL语句
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                datasource.push(conn);
            }
        }
        return rtn;
    }
	
}

6、新建dao工厂类,可扩展

public class DAOFactory {
	// 返回值为接口类型,等价于IAdStatDAO iAdStatDAO = new AdStatDAOImpl();
	public static IAdStatDAO getAdStatDAO() {
		return new AdStatDAOImpl();
	}
	public static IAdBlacklistDAO getAdBlacklistDAO() {
		return new AdBlacklistDAOImpl();
	}
}

7、对应的接口和实现类

接口

public interface IAdBlacklistDAO {	
	/**
	 * 查询所有广告黑名单用户
	 * @return
	 */
	List<AdBlacklist> findAll();	
}
public interface IAdStatDAO {

	void updateBatch(List<AdStat> adStats);
	
}

实现类

// 查询所有广告黑名单用户
public class AdBlacklistDAOImpl implements IAdBlacklistDAO {
	@Override
	public List<AdBlacklist> findAll() {
		String sql = "SELECT * FROM ad_blacklist"; 
		
		final List<AdBlacklist> adBlacklists = new ArrayList<AdBlacklist>();
		
		JDBCHelper jdbcHelper = JDBCHelper.getInstance();
		
		jdbcHelper.executeQuery(sql, null, new JDBCHelper.QueryCallback() {
			
			@Override
			public void process(ResultSet rs) throws Exception {
				while(rs.next()) {
					Long userid = Long.valueOf(String.valueOf(rs.getInt(1)));
					
					AdBlacklist adBlacklist = new AdBlacklist();
					adBlacklist.setUserid(userid); 
					
					adBlacklists.add(adBlacklist);
				}
			}
			
		});
		return adBlacklists;
	}
}


// 实时统计DAO实现类具体业务细节可略
public class AdStatDAOImpl implements IAdStatDAO {

	@Override
	public void updateBatch(List<AdStat> adStats) {
		JDBCHelper jdbcHelper = JDBCHelper.getInstance();
		
		// 区分开来哪些是要插入的,哪些是要更新的
		List<AdStat> insertAdStats = new ArrayList<AdStat>();
		List<AdStat> updateAdStats = new ArrayList<AdStat>();
		
		String selectSQL = "SELECT count(*) "
				+ "FROM ad_stat "
				+ "WHERE date=? "
				+ "AND province=? "
				+ "AND city=? "
				+ "AND ad_id=?";
		
		for(AdStat adStat : adStats) {
			final AdStatQueryResult queryResult = new AdStatQueryResult();
			
			Object[] params = new Object[]{adStat.getDate(),
					adStat.getProvince(),
					adStat.getCity(),
					adStat.getAdid()};
			
			jdbcHelper.executeQuery(selectSQL, params, new JDBCHelper.QueryCallback() {
				
				@Override
				public void process(ResultSet rs) throws Exception {
					if(rs.next()) {
						int count = rs.getInt(1);
						queryResult.setCount(count); 
					}
				}
				
			});
			
			int count = queryResult.getCount();
			
			if(count > 0) {
				updateAdStats.add(adStat);
			} else {
				insertAdStats.add(adStat);
			}
		}
		
		// 对于需要插入的数据,执行批量插入操作
		String insertSQL = "INSERT INTO ad_stat VALUES(?,?,?,?,?)";  
		
		List<Object[]> insertParamsList = new ArrayList<Object[]>();
	
		for(AdStat adStat : insertAdStats) {
			Object[] params = new Object[]{adStat.getDate(),
					adStat.getProvince(),
					adStat.getCity(),
					adStat.getAdid(),
					adStat.getClickCount()};
			insertParamsList.add(params);
		}
		
		jdbcHelper.executeBatch(insertSQL, insertParamsList);
		
		// 对于需要更新的数据,执行批量更新操作
		String updateSQL = "UPDATE ad_stat SET click_count=? "
				+ "FROM ad_stat "
				+ "WHERE date=? "
				+ "AND province=? "
				+ "AND city=? "
				+ "AND ad_id=?";
		
		List<Object[]> updateParamsList = new ArrayList<Object[]>();
		
		for(AdStat adStat : updateAdStats) {
			Object[] params = new Object[]{adStat.getClickCount(),
					adStat.getDate(),
					adStat.getProvince(),
					adStat.getCity(),
					adStat.getAdid()};
			updateParamsList.add(params);
		}
		
		jdbcHelper.executeBatch(updateSQL, updateParamsList);
	}
}

测试


public class TaskDAOTest {
	
	public static void main(String[] args) {
		IAdBlacklistDAO adBlacklistDAO = DAOFactory.getAdBlacklistDAO();
		List<AdBlacklist> adBlacklist = adBlacklistDAO.findAll();
		System.out.println(adBlacklist.getUserid());  

		IAdStatDAO adStatDAO = DAOFactory.getAdStatDAO();
		List<AdStat> adStats = new ArrayList<AdStat>();
		adStatDAO.updateBatch(adStats); 
	}
	
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值