此心不动,随机而动
Java第12天上午
上午主要复习了JDBC
详细内容可参见:
7.21 JDBC 学习总结
以下总结补充:
使用JDBC来操作数据库用到的类:
遍历数据库的大致步骤:
不遍历的话 则:
PreparedStatement优势绝不仅仅是更灵活的参数化查询
请参见:PreparedStatement VS Statement
上午完成的经典代码:(遍历数据)
import java.sql.*;
public class TestJDBC {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String Driver = "com.mysql.jdbc.Driver";
// 对应 第二步
String url = "jdbc:mysql://localhost:3306/itcast";
String user = "root";
String password = "root";
try{
// 第一步 先加载注册JDBC的驱动类
Class.forName(Driver);
// 第二步 提供JDBC连接的url
// 第三步 创建数据库的连接
conn = DriverManager.getConnection(url, user, password);
// 第四步 创建一个statement对象
stmt = conn.createStatement();
// 第五步 执行sql语句
rs = stmt.executeQuery("select * from student");
// 第六步 循环遍历处理结果
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("birth").subSequence(0, 4));
}
} catch(ClassNotFoundException s){
s.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
} finally {
// 第七步 关闭JDBC对象
try {
if(rs != null) {
rs.close();
}
if(stmt != null)(
stmt.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
上午完成的经典代码:(插入数据)
import java.sql.*;
public class TestDML {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
String Driver = "com.mysql.jdbc.Driver";
// 对应 下面第二步
String url = "jdbc:mysql://localhost:3306/itcast";
String user = "root";
String password = "root";
try{
// 第一步 先加载注册JDBC的驱动类
Class.forName(Driver);
// 第二步 提供JDBC连接的url
// 第三步 创建数据库的连接
conn = DriverManager.getConnection(url, user, password);
// 第四步 创建一个statement对象
//pstmt = conn.prepareStatement("insert into student values(7,'你好','男',17)");
pstmt = conn.prepareStatement("insert into student values(?,?,?,?,?)");
pstmt.setInt(1, 0);
pstmt.setString(2, "王33");
pstmt.setString(3, "男");
pstmt.setInt(4, 25);
pstmt.setString(5, "2017");
pstmt.executeUpdate();
} catch(ClassNotFoundException s){
s.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
} finally {
// 第七步 关闭JDBC对象
try {
if(pstmt != null) {
pstmt.close();
}
if(conn != null) {
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
下午主要学习了配置文件和连接池
Java配置文件
在上午代码基础上 我们考虑进一步优化代码结构
给定这样的数据库:
先来看之前创建连接的结构:
// 第一步 先加载注册JDBC的驱动类
String Driver = "com.mysql.jdbc.Driver";
Class.forName(Driver);
// 第二步 提供JDBC连接的url
String url = "jdbc:mysql://localhost:3306/itcast";
String user = "root";
String password = "root";
// 第三步 创建数据库的连接
conn = DriverManager.getConnection(url, user, password);
可见 我们每创建一个连接 就需要重现以上代码
并且在开发时 有些参数是经常改变的
比如操作数据库时 我们可能连接本地的数据库 那么IP 、数据库名称、表名称和数据库主机等信息是我们本地的。
要使得操作数据的模块具有通用性,那么以上信息就不能写死在程序里。通常我们的做法是用配置文件来解决
关于更多java配置文件说明 请看:.properties Java 配置文件
所以先来新建一个properties (Java配置文件):
先右击src文件夹 新建一个File
选File 再点击Next:
File名称设置为:db.properties
db.properties 文件新建成功:
可以点击右边的Add在弹窗中输入key - value 数据:
比如 我们输入 user - root 点击 Finish:
点击左下角的Source:
即我们也可以在Source中直接输入:(推荐做法)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/itcast
user=root
password=root
(左边是key 右边是value)
输入结果如图:
即目前我们成功把:
// 第一步 先注册加载JDBC的驱动类
String Driver = "com.mysql.jdbc.Driver";
Class.forName(Driver);
// 第二步 提供JDBC连接的url
String url = "jdbc:mysql://localhost:3306/itcast";
String user = "root";
String password = "root";
信息写到了 配置文件中
下面我们来看如何调用配置信息:
同样在 src 目录下 新建一个 JdbcUtil 类:
直接给出 JdbcUtil.java 代码:
import java.io.IOException;
import java.util.Properties;
import java.sql.*;
public class JdbcUtil {
private static String driver;
private static String url;
private static String uesrname;
private static String password;
static {
try{
Properties p = new Properties();
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
driver = p.getProperty("driver");
url = p.getProperty("url");
uesrname = p.getProperty("user");
password = p.getProperty("password");
Class.forName(driver);
}catch(IOException e){
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection createConnection(){
Connection conn = null;
try {
conn = DriverManager.getConnection(url, uesrname, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn, Statement stat,ResultSet rs) {
try {
if(rs != null){
rs.close();
}
if(stat != null){
stat.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
代码说明:
1 4个成员变量分别用来接收 从配置文件读到的内容
即
private static String driver;
private static String url;
private static String uesrname;
private static String password;
对应配置文件中 左边的4个key:
2 中间的 静态代码块 完成 :
-
获取配置文件的value:
注册加载JDBC的驱动类:
Class.forName(driver);
注意
Properties p = new Properties();
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
load方法可以从 .properties属性文件(这里是db.properties) 对应的文件输入流中,加载属性列表到Properties类对象(这里是p),即通过对上面的 properties 文件进行装载来获取该文件中的所有键 - 值对。以供 getProperty ( String key) 来搜索。
另外Thread.currentThread().getContextClassLoader().getResourceAsStream() 请看:读取配置文件Properties的一种方案
另外补充:
Java中普通代码块,构造代码块,静态代码块区别及代码示例
3 createConnection 方法:(创建数据库的连接)
public static Connection createConnection(){
Connection conn = null;
try {
conn = DriverManager.getConnection(url, uesrname, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
下面测试
在src 下新建一个Test.java文件:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
conn = JdbcUtil.createConnection();
String sql = "select * from student";
try{
stat = conn.createStatement();
rs = stat.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("age"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, stat, rs);
}
}
}
其中,我们以后可这样创建连接:
conn = JdbcUtil.createConnection();
(即利用JdbcUtil中的方法创建连接)
其中,我们也可以这样关闭资源:
JdbcUtil.close(conn, stat, rs);
即利用JdbcUtil中的close()方法关闭资源
JdbcUtil中的close()方法:
public static void close(Connection conn, Statement stat,ResultSet rs) {
try {
if(rs != null){
rs.close();
}
if(stat != null){
stat.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
运行一下Test.java文件 可见成功打印:
连接池
我们来考虑下通过配置文件创建连接的性能,在JdbcUtil类的createConnection()方法中利用系统的currentTimeMillis()函数获取前后用时:
运行可见用时476ms:
(不同电脑性能有差异,您的时间可能不同)
476ms已经不算少了 试想如果创建多个Connection 那么用时会很长,足以严重影响性能。
所以,我们提出连接池概念:
更多连接池概念请见:
1 - Java连接池详解
2 - 几个主流的Java连接池整理
一下不理解很正常,先有个概念:池技术是为了优化服务器应用程序的性能、提高程序执行效率和降低系统资源开销。
考虑下连接池的设计:
连接池(connection pool)
- 使用集合 将Connection对象放入List中,反复使用
- 连接池的初始化
- 事先放入多个连接对象
- 从连接池中获取连接对象
- 如果池中无可用连接,则创建一个新的
- 如果池中有可用连接,则将池中最后一个返回,同时,将该连接从池中remove,表示正在使用
- 关闭连接
- 不是真正的关闭,而是将用完的放回去
新建一个com.pool包 在包下新建 DBConnPool.java:
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import com.hkj.JdbcUtil;
public class DBConnPool {
// 连接对象
private static List pool;
// 最大连接数
private static final int POOL_MAX_SIZE = 100;
// 最小连接数
private static final int POOL_MIN_SIZE = 10;
public DBConnPool(){
initPool();
}
// 初始化连接池 让池中的连接数达到最小值
public void initPool(){
if(pool == null){
pool = new ArrayList();
}
while(pool.size() < POOL_MIN_SIZE){
pool.add(JdbcUtil.createConnection());
System.out.println("初始化池,池中连接数:"+pool.size());
}
}
// 从池取最后一个连接
public synchronized Connection getConnection(){
Connection conn = null;
int last_index = 0;
if(pool.size() == 0) {
pool.add(JdbcUtil.createConnection());
}
last_index = pool.size()-1;
conn = pool.get(last_index);
pool.remove(last_index);
return conn;
}
// 将连接池放回池中
public synchronized void close(Connection conn){
if(pool.size() >= POOL_MAX_SIZE){
try {
if(conn != null){
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}else{
pool.add(conn);
}
}
}
注意:
在此初始化方法中 循环add 以让池中的连接数达到最小值
TestPool.java代码:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.pool.DBConnPool;
public class TestPool {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
DBConnPool dbpool = new DBConnPool();
conn = dbpool.getConnection();
String sql = "select * from student";
try{
stat = conn.createStatement();
rs = stat.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("age"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
dbpool.close(conn);
}
}
}
主要代码——新建连接池对象:
DBConnPool dbpool = new DBConnPool();
利用连接池对象的getConnection()获取一个连接:
conn = dbpool.getConnection();
利用连接池对象的close()将连接池放回池中:
dbpool.close(conn);
一定注意 close并不是真的关掉 而是放回池:
拓展阅读:
Java中Synchronized的用法
世界上所有的追求都是因为热爱
一枚爱编码 爱生活 爱分享的IT信徒
— hongXkeX