# 也可以是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
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);
}
}
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";
}
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;
}
}
public class DAOFactory {
// 返回值为接口类型,等价于IAdStatDAO iAdStatDAO = new AdStatDAOImpl();
public static IAdStatDAO getAdStatDAO() {
return new AdStatDAOImpl();
}
public static IAdBlacklistDAO getAdBlacklistDAO() {
return new AdBlacklistDAOImpl();
}
}
接口
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);
}
}