一、传统JDBC:
/**
* 释放资源
*
* @param rs
* @param st
* @param conn
*/
public static void free(ResultSet rs, Statement st, Connection conn) {
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null)
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public static Connection getConn() {
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
String username = "scott";
String password = "tiger";
Connection conn = null;
try {
Class.forName(driver); // classLoader,加载对应驱动
conn = (Connection) DriverManager.getConnection(url, username,
password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static int insertAndDelete(String sql) {
Connection conn = getConn();
int i = 0;
PreparedStatement pstmt = null;
try {
pstmt = (PreparedStatement) conn.prepareStatement(sql);
i = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return i;
}
public static List queryForList(String sql) {
System.out.println("queryForList=======" + sql);
Connection conn = getConn();
PreparedStatement pstmt = null;
List<Map> list = new ArrayList();
try {
pstmt = (PreparedStatement) conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
int col = rs.getMetaData().getColumnCount();// 记录数
while (rs.next()) {
Map<String, Object> map = new HashMap();
for (int i = 1; i <= col; i++) {
map.put(rs.getMetaData().getColumnName(i),
rs.getObject(i) == null ? "" : rs.getObject(i));
}
list.add(map);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
/**
sql2 = "{call wzx_update_word()}";
**/
public static int doProcedure(String sql) {
Connection conn = getConn();
CallableStatement statement = null;
try {
statement = conn.prepareCall(sql);
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCTool.free(null, statement, conn);
}
return 0;
}
传统JDBC优缺点:
优点:1.简单,一个java类就可以开始操作数据库。
2. sql灵活,sql随便写,需要传值就填问号即可。
3.原始框架直接操作数据库,效率高。
缺点: 1.安全性不高,SQL注入等。
2.查询体验差(很难获得bean,或List<bean>)。
3.连接使用释放难控制,万一程序异常连接没有释放,造成数据库内存泄漏,需要重启数据库。
4.不适用大型应用,成千上万个人申请连接,再断开,会占用系统资源,严重的会造成服务器崩溃。
二、连接池
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,使用完再放回到连接池中,而不是重新建立一个。连接池在初始化时将创建一定数量的数据库连接放到连接池中。
小提示:oracle数据库最大连接数默认150,也就是最多创建150个connection。
知识扩展:connection实际上就是一个socket请求发送到数据库进行通信。
为什么要使用连接池?
首先,没有连接池的情况
1.如果程序出现异常,连接没有释放,造成数据库内存泄漏,只能重启数据库。
2.几百万用户请求,频繁连接和释放会消耗资源,导致服务器变慢。为什么会消耗资源?因为创建连接时耗资源(比如进行分配内存的工作),大用户数时就会影响网站响应速度。
3.和第1点类似,可以无限创建连接,导致数据库内存泄漏。
使用连接池
连接池允许程序重复使用已有的connection,而不用重新创建。当有事务开始时,就从连接池中取一个可用的进行事务处理,没有时则等待;事务处理完毕后再将连接放回连接池中
解决了什么问题?
1.连接的释放由连接池控制,不担心内存泄漏。
2.connection重复利用,减少创建连接导致的资源消耗。
如果并发超过连接池连接数,则链接排队等待,直到空出链接。
如果并发远远大于一个数据库的承受能力,怎么办?
第一 , 可以 增加 缓存,减少查询连接。
第二, 可以部署数据库集群,读写分离。
第三, 使用微服务,一个服务使用一个数据库。
第四,如果插入太多,也可以使用消息队列,先把要插入的数据保存到队列中,然后定时插入到数据库。