Java与数据库连接篇
课程内容:
一、什么是JDBC?(What)
JDBC(Java Data Base Connectivity,Java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
Java对外指定一些编程标准,其它数据库服务器厂商按照这个标准,编写对应的实现方案。这样对于Java程序员而言,只需要学习Java的标准即可,不需要了解不同厂商的实现细节。一切操作都是在学习接口开发。按照接口指定的标准完成指定需要完成的业务即可。
二、为什么要使用JDBC?(Why)
- 为了将数据持久的存储、固化到磁盘上我们需要掌握数据库。
- 为了通过Java代码完成对于数据的持久存储我们需要学习JDBC。
- 通过JDBC我们能够以面向接口方式,操作数据库中的数据,更加的方便。
- 本身Java就是跨平台的,通过Java开发的JDBC应用可以在不同的平台上执行。
- JDBC为数据库开发提供了标准的API,所以使用JDBC开发的数据库应用也可以跨数据库(要求全部使用标准的SQL)
JDBC和ODBC的区别和联系:
ODBC:
它使用 C 语言接口,是一组对数据库访问的标准API,这些API通过SQL来完成大部分任务,而且它本身也支持SQL语言,支持用户发来的SQL。ODBC定义了访问数据库API的一组规范,这些API独立于形色各异的DBMS和编程语言。
JDBC:
是Java与数据库的接口规范,JDBC定义了一个支持标准SQL功能的通用低层API,它由Java 语言编写的类和接口组成,旨在让各数据库开发商为Java程序员提供标准的数据库API。
常见JDBC驱动:
- JDBC-ODBC桥(JDBC-ODBC Bridge Driver)
- 最早实现的JDBC驱动程序,旨在快速推广,将JDBC-API映射为ODBC-API。JDK8中已经移除
- JDBC API驱动程序(Anative API partly Java technology-enabled Driver)
- 需要实现本地安装特定的驱动程序,通过转换把Java编写的JDBC-API转换为Native-API,进行数据库操作。
- 纯Java的数据库中间件驱动程序(Pure Java Driver for Database Middleware)
- 不需要安装特定的驱动程序,需要在安装数据库管理系统的服务器端安装中间件(Middleware),中间件负责在存取数据时必要的转换操作。就是将JDBC访问转换为数据库无关的http或者是https协议,再有中间件转换为数据库专用的访问指令。
- 纯Java的JDBC驱动程序(Direct-to-DatabasePureJavaDriver)
- 目前最流行的JDBC驱动,不需要安装任何附加内容,所有存取数据库的操作都直接由JDBC驱动程序来完成,此类驱动程序能将JDBC调用转换成DBMS专用的网络协议,能够自动识别网络协议下的特殊数据库并能直接创建数据连接。
三、 在那些场景下需要使用JDBC(Where)
Java程序员如果想要和数据库打交道就必须要掌握JDBC。
如果你的业务模型中需要将数据持久化存储就必须掌握JDBC。
四、 如何使用JDBC?(How)
1. JDBC所处的处境?
2.编写第一个JDBC程序
1) 连接步骤
1) 手动导入需要连接数据库的jar包
2) 加载驱动
3) 创建连接对象
4) 声明sql语句
5) 创建处理sql语句对象
6) 发送sql语句,接收返回结果
7) 处理结果
8) 关闭资源连接
2) 导入需要的jar包
连接oracle就导入jdbc的jar包,参照附录到安装对应数据库可以在内部找到jar包;
连接mysql就导入mysql-connector的jar包,到官网下载对应版本jar包,或在maven仓库下载jar包。
3) 编写测试代码
@Test
public void searchOne() {
//提升作用域 方便后期关闭资源
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2:获取连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/note",
"root","root");
//3:声明sql语句
String sql = "SELECT * FROM TB_USER WHERE ID = 1";
//4:创建处理对象
stmt = conn.createStatement();
//5:发送sql语句获取结果集(如果是查询操作才存在结果集)
rs = stmt.executeQuery(sql);
//6. 迭代结果集
while(rs.next()) {
//7:分析结果集
System.out.println(rs.getString("name"));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//8:关闭资源
try {
if(rs!=null)
rs.close();
if(stmt!=null)
stmt.close();
if(conn!=null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4) 分析第一个程序
A. 为什么要加载驱动?
I. 通过Class.forName("Driver类的路径名");
II.查看Mysql的Driver类
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
//在初始化的时候,就将当前数据库对象的驱动加载到sql的注册中心中去
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
B.获取连接源码
//获取连接就是会将连接信息包装为Properties
public static Connection getConnection(String url,
String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
if (user != null) {
info.put("user", user);
}
if (password != null) {
info.put("password", password);
}
return (getConnection(url, info, Reflection.getCallerClass()));
}
C.常见对象:
对象名称获取方式用途DriverManager用来管理JDBC驱动的服务类,主要用来获取Connection。ConnectionDriverManager.getConnection(url,name,pwd);代表一个物理连接会话,如果要操作数据库必须先获取数据库连接对象。StatementConnection.createStatement();用于执SQL语句的对象。常见的有Statement、PreparedStatement、CallableStatementResultSet(针对查询)Statement.executQuery(sql);结果集对象,包含了对于访问查询结果的方法。
3. 修改操作
3.1测试用例编写
@Test
public void updateNameById() {
//1:声明用户修改的id
Integer id = 1;
//2:声明修改后的名称
String newName= "大锤";
//3:声明连接对象
Connection conn = null;
Statement stmt = null;
try {
//4:加载驱动
Class.forName("com.mysql.jdbc.Driver");
//5:获取连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/note",
"root","root");
stmt = conn.createStatement();
//6:声明sql语句
String sql = "UPDATE TB_USER SET NAME = '"+newName+"'WHERE USERID = "+id;
//7:发送sql语句 接受返回结果
int rows = stmt.executeUpdate(sql);
System.out.println("修改了"+rows+"行记录");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//8:关闭资源
try {
if(stmt!=null) {
stmt.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
3.2 注意事项
1. 修改操作返回的是受影响的行数
2. 加载驱动只需要一次,不需要每次都加载驱动
4. 删除操作
4.1 测试用例编写
public class JDBCTest01 {
Connection conn = null;
Statement stmt = null;
@Before
public void load() {
//1:加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void deleteById() {
try {
//5:获取连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/note",
"root","root");
stmt = conn.createStatement();
//6:声明sql语句
String sql = "DELETE FROM TB_USER WHERE ID = 1";
//7:发送sql语句 接受返回结果
int rows = stmt.executeUpdate(sql);
System.out.println("删除了"+rows+"行记录");
} catch (SQLException e) {
e.printStackTrace();
}
}
@After
public void close() {
try {
if(stmt!=null) {
stmt.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4.2 注意事项
* 1:删除操作作为DML语句的一种,返回的也是受影响的行数。
5. 增加操作
5.1 测试用例编写
public class JDBCTest01 {
Connection conn = null;
Statement stmt = null;
@Before
public void load() {
//1:加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void insert() {
try {
User u = new User("wangdachui", "123456",'王大锤', 18, "男");
//5:获取连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/note",
"root","root");
stmt = conn.createStatement();
//6:声明sql语句
String sql = "INSERT INTO TB_USER (UNAME,UPWD,NAME,AGE,GENDER) VALUES ('"+u.getUname()+"','"+u.getUpwd()+"','"+u.getName()+"','"+u.getAge() + "','" + u.getGender() + "')";
//7:发送sql语句 接受返回结果
int rows = stmt.executeUpdate(sql);
System.out.println("增加了"+rows+"行记录");
} catch (SQLException e) {
e.printStackTrace();
}
}
@After
public void close() {
try {
if(stmt!=null) {
stmt.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
User.java内容如下:
package com.mage.po;
/*
* javabean规范:
* 所有属性私有
* 所有私有属性提供public的setter、getter方法
* 提供至少空构造器
*/
public class User {
private int id;
private String uname;
private String upwd;
private String name;
private String gender;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpwd() {
return upwd;
}
public void setUpwd(String upwd) {
this.upwd = upwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(int id, String uname, String upwd, String name, String gender, int age) {
super();
this.id = id;
this.uname = uname;
this.upwd = upwd;
this.name = name;
this.gender = gender;
this.age = age;
}
}
5.2 注意事项
删除也是返回受影响的行数
注意:对于所有的写操作(增、删、改),其实主体内容都差不多,主要是sql语句不同,某些参数不同,后期是可以考虑封装起来的。
6. 查询操作
6.1 测试用例编写
public class JDBCTest01 {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
@Before
public void load() {
//1:加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void insert() {
LinkedList<User> list = new LinkedList<User>();
try {
//5:获取连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/note",
"root","root");
stmt = conn.createStatement();
//6:声明sql语句
String sql = "SELECT * FROM TB_USER";
//7:发送sql语句 接受返回结果
rs = stmt.executeQuery(sql);
//8:分析结果集
while(rs.next()) {
User u = new User();
u.setId(rs.getInt("id"));
u.setUname(rs.getString("uname"));
u.setUpwd(rs.getString("upwd"));
u.setName(rs.getString("name"));
u.setAge(rs.getInt("age"));
u.setGender(rs.getString("gender"));
list.add(s);
}
System.out.println(ls);
} catch (SQLException e) {
e.printStackTrace();
}
}
@After
public void close() {
try {
if(rs!=null) {
rs.close();
}
if(stmt!=null) {
stmt.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
6.2 注意事项
1:对于DQL操作,返回的是结果集ResultSet对象
2:对于ResultSet对象,需要通过.next()方法,查看是否存在其他记录
五、附录
1. Statement对象的问题
1.1 效率问题
- 正常情况下插入:
问题描述:插入100000条数据,通过Statement插入:root 插入数据:1000,用时:2200
插入数据:1000,用时:2769
插入数据:1000,用时:2943
public class JDBCTest02 {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<User> data = new LinkedList<>();
@Before
public void load() {
try {
//1:加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2:编写测试数据
for(int i = 1;i<100000;i++) {
String uname = "zs"+i;
String upwd = "123";
String name = "张三"+i;
int age = (int)(Math.random()*7+18);
String gender = (int)(Math.random())>0.5?"女":"男";
User u = new User(uname, upwd,name, age, gender);
data.add(u);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void insert() {
try {
//5:获取连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/note",
"root","root");
stmt = conn.createStatement();
//记录时间
long startTime = System.currentTimeMillis();
int rows = 0;
for(int i = 1;i<data.size();i++) {
//6:声明sql语句
String sql = "INSERT INTO TB_User (UNAME,UPWD,NAME,AGE,GENDER) VALUES ('"+
data.get(i).getUname()+"','"+data.get(i).getUpwd()+"','"+ data.get(i).getName()+"','"+ data.get(i).getAge() +"','"+ data.get(i).getGender()+"')";
//7:发送sql语句 接受返回结果
rows += stmt.executeUpdate(sql);
}
//记录时间
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime+"ms,总共受影响的行数是:"+rows);
} catch (SQLException e) {
e.printStackTrace();
}
}
@After
public void close() {
try {
if(stmt!=null) {
stmt.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
结论:
399050ms,总共受影响的行数是:100000
- 通过PreparedStatement插入数据
通过PreparedStatement插入数据
测试用例:
public class JDBCTest03 {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List<User> data = new LinkedList<User>();
@Before
public void load() {
try {
//1:加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2:编写测试数据
for(int i = 1;i<100000;i++) {
String uname = "zs"+i;
String pwd = "123";
String name = "张三"+i;
int age = (int)(Math.random()*7+18);
String gender = (int)(Math.random())==0?"女":"男";
User u = new User(uname, pwd,name, age, gender);
data.add(u);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void insert() {
int rows = 0;
try {
//5:获取连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/note",
"root","root");
//6:声明sql语句
String sql = "INSERT INTO TB_USER(UNAME,UPWD,NAME,AGE,GENDER) VALUES (?,?,?,?,?)";
//7:获取预处理对象
pstmt = conn.prepareStatement(sql);
//记录时间
long startTime = System.currentTimeMillis();
//循环获取到每个对象的内容
for(int i = 0;i<data.size();i++) {
//8:设置绑定变量
pstmt.setString(1,data.get(i).getUname());
pstmt.setString(2,data.get(i).getUpwd());
pstmt.setString(3,data.get(i).getName());
pstmt.setInt(4,data.get(i).getAge());
pstmt.setString(5,data.get(i).getGender());
//9:发送SQL语句 获取结果
rows += pstmt.executeUpdate();
}
//记录时间
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime+"ms,总共受影响的行数是:"+rows);
} catch (SQLException e) {
e.printStackTrace();
}
}
@After
public void close() {
try {
if(pstmt!=null) {
pstmt.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
结论:
677875ms,总共受影响的行数是:100000
- 通过PreparedStatement批处理以及事务插入数据
通过PreparedStatement批处理插入数据
测试用例:
public class JDBCTest03 {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List<Student> data = new LinkedList<>();
@Before
public void load() {
try {
//1:加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2:编写测试数据
for(int i = 1;i<100000;i++) {
String name = "用户"+i;
String pwd = "123";
int age = (int)(Math.random()*7+18);
String gender = (int)(Math.random())>0.5?"女":"男";
Student stu = new Student(name, pwd, age, gender);
data.add(stu);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void insert() {
int rows = 0;
try {
//5:获取连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/note?rewriteBatchedStatements=true",
"root","root");
//6:声明sql语句
String sql = "INSERT INTO TB_USER(UNAME,UPWD,NAMW,AGE,GENDER) VALUES (?,?,?,?,?)";
//7:获取预处理对象
pstmt = conn.prepareStatement(sql);
//记录时间
long startTime = System.currentTimeMillis();
//关闭自动提交事务
conn.setAutoCommit(false);
//循环获取到每个对象的内容
for(int i = 0;i<data.size();i++) {
//8:设置绑定变量
pstmt.setString(1,data.get(i).getUname());
pstmt.setString(2,data.get(i).getUpwd());
pstmt.setString(3,data.get(i).getName());
pstmt.setInt(4,data.get(i).getAge());
pstmt.setString(5,data.get(i).getGender());
//添加到批处理中
pstmt.addBatch();
}
//一起提交到数据库服务器
rows = pstmt.executeBatch().length;
//提交事务
conn.commit();
//记录时间
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime+"ms,总共受影响的行数是:"+rows);
} catch (SQLException e) {
try {
//出现异常则回滚事务
conn.rollback();;
e.printStackTrace();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
@After
public void close() {
try {
if(pstmt!=null) {
pstmt.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
结论:
188114ms,总共受影响的行数是:100000
- Tips
- 使用批处理需要增加rewriteBatchedStatements=true
- 将所有批量操作添加到一个事务当中,设置自动提交为false;conn.setAutoCommite(false);
- 如果语句中出现问题,则在异常中对于事务进行回滚。
1.2 SQL注入问题
测试代码:
public class JDBCTest04 {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
public static final String URL = "jdbc:mysql://localhost:3306/note";
public static final String USER_NAME = "root";
public static final String USER_PWD = "root";
//模拟登陆用户
User user = null;
@Before
public void load() {
try {
//1:加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2:模拟用户数据,这里记得在User.java中添加对应构造器
user = new User("'1","' or 1=1");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void queryByUser() {
int rows = 0;
try {
//5:获取连接对象
conn = DriverManager.getConnection(
URL, USER_NAME,USER_PWD);
//6:声明sql语句
String sql = "SELECT * FROM TB_STUDENT WHERE UNAME = "+loginStu.getUname()
+" AND PWD = "+loginStu.getUpwd();
System.out.println(sql);
//7:获取处理对象
stmt = conn.createStatement();
//8:发送sql 获取结果
rs = stmt.executeQuery(sql);
//9:分析结果
while(rs.next()) {
System.out.println("查询到了结果");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
@After
public void close() {
try {
if(stmt!=null) {
stmt.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
结论:
- 通过构建sql语句,导致不同的用户名和密码侵入到系统内部,就是SQL注入攻击。
- 为了防止出现这个问题,我们通过预处理对象完成,PreparedStatement。
2. 常见方法总结
常见对象对象常见方法作用ConnectionConnection.createStatement();创建Statement对象Connection.preparedStatement(sql);创建预处理对象Connection.prepareCall(sql)创建CallableStatement对象,调用存储过程Connection.setAutoCommite(true/false)设置事务提交方式,默认情况是自动提交trueConnection.commit();提交事务Connection.rollback();回滚事务StatementStatement.executeQuery(sql);针对查询操作,获取结果集对象Statement.executeUpdate(sql);针对写(增加、删除、修改)操作,获取受影响的行数PreparedStatementPreparedStatement.executeQuery();针对查询操作,获取结果集对象PreparedStatement.executeUpdate();针对写(增加、删除、修改)操作,获取受影响的行数PreparedStatement.addBatch();添加到批处理中PreparedStatement.executeBatch();执行批处理操作PreparedStatement.setXXX(index,value);设置绑定变量,给指定的占位符index,指定具体的值value,XXX代表value的数据类型。注意index从1开始ResultSetResultSet.next();查看读操作返回的结果集中是否还存在数据信息ResultSet.getXXX(index/columnName);根据字段的顺序或者是字段名称获取结果集中该字段的值,XXX代表返回数据的类型。index获取列是从0开始
3. Statement和PreparedStatement对比
区别点对象具体细节创建方式StatementConnection.createStatement(); 不需要sqlPreparedStatementConnection.preparedStatement(sql);需要sql安全Statement不能防止sql注入<br />SELECT * FROM TB_USER WHERE UNAME = '1 AND PWD = ' OR 1=1 PreparedStatement可以防止SQL注入效率Statement不会初始化,没有预处理,每次都是从0开始执行SQPreparedStatement会先初始化SQL,先把这个SQL提交到数据库中进行预处理,多次使用可提高效率可读性Statement当多次执行参数不同的语句时,需要不断的拼接字符串,使得阅读变得极为耗时以及费力。PreparedStatement通过SetXXX();这样的方式,提高了阅读性性能Statement没有预编译的过程,每次都需要在DB中重新编译一下PreparedStatement语句被db的编译器编译后的执行代码就会被缓存下来, 那么下次调用时只要相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行就可以。 相当于一个函数 , 对于整个db来说,只有预编译的语句和缓存中匹配,那么任何时候,就可以不需要再次编译从而直接执行。并不是所有的预编译语句都会被缓存起来,数据库本身会用一种策略,频繁使用的语句可能被缓存起来,以保存有更多的空间存储新的预编译语句。
3. DBUtiles编写
1) 编写步骤注释
1在src下创建一个.properties文件,编写驱动、链接地址、用户名、密码
2在工具类中通过流的方式读取配置文件信息,获取驱动、链接地址、用户名、密码
3编写获取连接、处理对象的方法
4编写资源连接的方法
2) 具体编码
配置文件DBConfig.properties
database=mysql
#######mysql properties########
mysqlDriver=com.mysql.jdbc.Driver
mysqlUrl=jdbc:mysql://localhost:3306/note
mysqlUsername=root
mysqlPassword=root
#######oracle properties########
oracleDriver=oracle.jdbc.OracleDriver
oracleUrl=jdbc:oracle:thin:@localhost:1521:orcl
oracleUsername=scott
oraclePassword=tiger
编写DBBase接口
public interface DBBase {
public static final String DATABASE_NAME = "database";
public static final String DATABASE_DRIVER = "driver";
public static final String DATABASE_URL = "url";
public static final String DATABASE_USERNAME = "username";
public static final String DATABASE_PASSWORD = "password";
}
编写DBUtils工具类
public class DBUtils {
//声明获取值
private static String database = "";
private static String driver = "";
private static String url = "";
private static String uname = "";
private static String pwd = "";
private static Properties pro = null;
//通过静态代码块将配置文件信息加载进来
static {
try {
//创建配置对象
pro = new Properties();
//获取输入流读取
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("DBConfig.properties");
//读取数据信息
pro.load(is);
//通过方法获取配置文件中的数据信息
database = getValue(DBBase.DATABASE_NAME);
driver = getValue(database+"-"+DBBase.DATABASE_DRIVER);
url = getValue(database+"-"+DBBase.DATABASE_URL);
uname = getValue(database+"-"+DBBase.DATABASE_USERNAME);
pwd = getValue(database+"-"+DBBase.DATABASE_PASSWORD);
//加载驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("驱动类为【"+driver+"】");
}
}
/**
* 获取连接对象
* @return
*/
public static Connection getConn() {
Connection conn = null;
try {
conn = DriverManager.getConnection(url, uname,pwd);
} catch (SQLException e) {
e.printStackTrace();
System.out.println("【"+url+"】【"+uname+"】【"+pwd+"】");
}
return conn;
}
/**
* 创建Statement对象
* @param conn
* @return
*/
public static Statement getState(Connection conn) {
if(conn==null)
throw new RuntimeException("连接为空");
Statement stmt = null;
try {
stmt = conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
System.out.println("创建Statement对象失败");
}
return stmt;
}
//关闭连接
private static void closeConn(Connection conn) {
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//关闭资源
private static void closeStmt(Statement stmt) {
if(stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//关闭资源
private static void closeRs(ResultSet rs) {
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//关闭所有资源
public static void closeAll(Connection conn,Statement stmt,ResultSet rs) {
closeRs(rs);
closeStmt(stmt);
closeConn(conn);
}
private static String getValue(String key) {
if("".equals(key)||key==null)
throw new NullPointerException("key值有误");
return pro.getProperty(key);
}
}
总结
1:通过Properties来加载配置文件信息。
2:通过getContextClassLoader().getResourceAsStream()读取相对于项目根目录下的资源文件。(这里的ClassLoader是一个上下文的加载器)。
3:在获取Properties中的值时,通过异常中断去处理了程序
4:通过静态代码块保证加载驱动只需要执行一次