jdbc.driver=com.mysql.cj.jdbc.Driver
package com.csdn.mymvc.dao;
import com.alibaba.druid.pool.DruidDataSource;
import com.csdn.mymvc.util.ClassUtil;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Properties;
public abstract class BaseDao {
private String entityClassName;
ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
Type actualTypeArgument = actualTypeArguments[0];
entityClassName = actualTypeArgument.getTypeName();
private DataSource dataSource;
private void initDataSource() {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
properties.load(inputStream);
String driver = properties.getProperty("jdbc.driver", "com.mysql.cj.jdbc.Driver");
String url = properties.getProperty("jdbc.url", "jdbc:mysql:///fruitdb");
String user = properties.getProperty("jdbc.user", "root");
String pwd = properties.getProperty("jdbc.pwd", "123456");
Integer initSize = Integer.parseInt(properties.getProperty("jdbc.init_size", "5"));
Integer maxActive = Integer.parseInt(properties.getProperty("jdbc.max_active", "10"));
Integer maxWait = Integer.parseInt(properties.getProperty("jdbc.max_wait", "5000"));
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(user);
druidDataSource.setPassword(pwd);
druidDataSource.setInitialSize(initSize);
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMaxWait(maxWait);
dataSource = druidDataSource;
} catch (IOException e) {
throw new RuntimeException(e);
private Connection getConn() throws SQLException {
return dataSource.getConnection();
private void close(Connection conn, PreparedStatement psmt, ResultSet rs) {
if (conn != null && !conn.isClosed()) {
} catch (SQLException e) {
throw new RuntimeException(e);
protected int executeUpdate(String sql, Object... params) {
boolean insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
PreparedStatement psmt = null;
psmt = insertFlag ? conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS) : conn.prepareStatement(sql);
int count = psmt.executeUpdate();
ResultSet rs = psmt.getGeneratedKeys();
} catch (SQLException e) {
throw new RuntimeException(e);
private void setParams(PreparedStatement psmt, Object... params) throws SQLException {
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
psmt.setObject(i + 1, params[i]);
protected List executeQuery(String sql, Object... params) {
List list = new ArrayList<>();
PreparedStatement psmt = null;
psmt = conn.prepareStatement(sql);
rs = psmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
T t = (T) ClassUtil.createInstance(entityClassName);
int columnCount = rsmd.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String columnName = rsmd.getColumnLabel(i);
Object columnValue = rs.getObject(i);
ClassUtil.setProperty(t, columnName, columnValue);
} catch (SQLException e) {
throw new RuntimeException(e);
protected T load(String sql, Object... params) {
PreparedStatement psmt = null;
psmt = conn.prepareStatement(sql);
rs = psmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
T t = (T) ClassUtil.createInstance(entityClassName);
int columnCount = rsmd.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
String columnName = rsmd.getColumnLabel(i);
Object columnValue = rs.getObject(i);
ClassUtil.setProperty(t, columnName, columnValue);
} catch (SQLException e) {
throw new RuntimeException(e);
protected List
List
PreparedStatement psmt = null;
psmt = conn.prepareStatement(sql);
rs = psmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
Object[] arr = new Object[columnCount];
for (int i = 1; i <= columnCount; i++) {
Object columnValue = rs.getObject(i);
arr[i - 1] = columnValue;
} catch (SQLException e) {
throw new RuntimeException(e);


- 只有增删改查方法才去处理异常,其他的辅助性的方法都直接往外抛 ,因为这些方法将来都会在增删改查方法里面去调用

- 一旦我们用数据源连接池对象技术,这里的 conn.close() 就不是真正的关闭,而是把这个对象重新归还给池子,我们把这个称为面向对象的多态现象,说明他仅仅是把他的一个标签从正在使用设置为空闲,但是这个对象没有关闭,这个close()相当于是一个多态。

- 真正的实现类是DruidPooledConnection,德鲁伊池子的连接,下面是close方法的源码
public void close() throws SQLException {
DruidConnectionHolder holder = this.holder;
if (this.dupCloseLogEnable) {
DruidAbstractDataSource dataSource = holder.getDataSource();
boolean isSameThread = this.getOwnerThread() == Thread.currentThread();
dataSource.setAsyncCloseConnectionEnable(true);
if (dataSource.isAsyncCloseConnectionEnable()) {
} else if (CLOSING_UPDATER.compareAndSet(this, 0, 1)) {
Iterator var4 = holder.getConnectionEventListeners().iterator();
List filters = dataSource.getProxyFilters();
if (filters.size() > 0) {
FilterChainImpl filterChain = new FilterChainImpl(dataSource);
filterChain.dataSource_recycle(this);
ConnectionEventListener listener = (ConnectionEventListener)var4.next();
listener.connectionClosed(new ConnectionEvent(this));
CLOSING_UPDATER.set(this, 0);
