一、介紹
Java DataBase Connectivity--java数据库连接技术,简称JDBC,可以为多种关系数据库提供统一访问,它由一组用java语言编写的类和接口组成。 同时,也是一个“低级”接口,在其之上可以使用“高级”接口,更方便的连接数据库。
原理
JDBC负责提供接口数据库厂商使用自己数据库的特点来实现接口。 程序员调用接口,实际上底层调用数据库厂商实现的部门实际工作过程,編寫類之前要引入jar包,在工程的目录下创建一个lib文件夹用来存放jar包
- 加载驱动,建立连接
- 获取Sql语句执行对象
- 执行SQl语句
- 处理结果集
- 关闭连接
二、接口与类型
驱动管理类型:DriverManager
static Connection getConnection(url,user,password) 通过地址,数据库用户名,用户密码 获取连接对象
连接接口:Connection
Statement createStatement() 获取一个SQL语句编译对象
PreparedStatement prepareStatement(String sql) 获取一个SQL语句预编译对象(可防止一些sql注入)
SQL语句对象接口:
Statement 用于编译静态SQL语句(编译多次)。
boolean execute(String sql) 用来执行DDL语言
ResultSet executeQuery(String sql) 用于执行DQL语言
int executeUpdate(String sql) 用于执行DML语言
void addBatch(String sql) 添加批处理
int[] executeBatch() 执行批处理
PreparedStatement 用于编译静态SQL语句,是Statement的一个子类型,执行效率比Statement要高(只编译一次)
boolean execute() 用来执行DDL语言
ResultSet executeQuery() 用来执行DQL语言
int executeUpdate() 用于执行DML语言
void addBatch() 添加批处理
int[] executeBatch() 执行批处理
结果集接口:ResultSet 在进行DQL操作时, 将查询的所有记录信息封装到ResultSet对象中 .
boolean next() 询问结果集对象中是否有下一行记录。如果返回true,光标会自动移到下一行。
还提供了一些数据库类型转java数据类型的方法:
int getInt(int columnIndex)/getInt(String columnName)
double getDouble(int columnIndex)/getDouble(String columnName)
String getString(int columnIndex)/getString(String columnName)
Date getDate(int columnIndex)/getDate(String columnName)
三、工具类的封装DBUtil
每次連接數據庫時都需要加载驱动,建立链接。其中的参数我们书写的次数比较多。
方法1:为了方便,为了节省资源,我们可以使用静态块来加载驱动,将参数值当成类的静态属性进行封装。 (加载一次就可以)
方法2:使用Properties 读取配置文件里的信息(将可能需要改变的信息存储在配置文件中)
方法2代碼:
public class DBUtil {
private static String drive;
private static String url;
private static String user;
private static String pass;
static {
try {
InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(is);
drive = prop.getProperty("driver");
url = prop.getProperty("url");
user = prop.getProperty("user");
pass = prop.getProperty("pass");
Class.forName(drive);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 連接數據庫
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, pass);
}
/**
* 關閉連接
*/
public static void closeConnection(Connection conn) {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 测试连接是否成功
*/
public static void main(String[] args) {
Connection conn = null;
try {
conn = DBUtil.getConnection();
System.out.println(conn);
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closeConnection(conn);
}
}
}
配置文件(配置文件db.properties内容是MySQL和Oracle的):
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/bd1802 user=root pass=123456 #driver=oracle.jdbc.driver.OracleDriver #url=jdbc:oracle:thin:@localhost:1521:xe #user=scott #pass=tijer
异常
jdbc发生的异常一般都是SQLException或者是其子类异常是检查性异常。 使用try-catch机制处理一下。finally里通常用来进行关闭数据库操作。
四、PreparedStatement的用法
在使用Statement时,因为Statement会对静态SQL语句进行编译。有可能会改变SQL语句的结构。因此有SQL注入安全隐患。(SQL注入参考:=======================================)
用法:可以对静态SQL语句使用问号"?"充当占位符。
如: select * from login_info where login_user = ? and login_pwd= ?使用此类中提供的类型转换方法进行给问号赋值
ps.setInt(int parameterIndex,int value) ps.setDouble(int parameterIndex,double value) ps.setString(int parameterIndex,String value) ps.setDate(int parameterIndex,Date value)
五、批处理
JDBC对事务的支持
事务要满足四个条件:ACID
原子性:一个事务,要么成功,要么回滚(撤回)
一致性:事务开始前的数据要和结束后的数据保持一致。
隔离性:一个事务正在进行,另外的事务要等待。
持久性:事务提交后,数据的改变是永久性的。
JDBC对DML语言的操作是默认提交的。当有多个DML操作时,我们应该取消自动提交 。改为手动提交
Connection接口提供了一个方法
void setAutoCommit(boolean flag) true:表示自动提交,false:表示取消自动提交
void commit() 提交事务
void rollback() 事务回滚
批处理
在进行插入数据操作时,有的时候,一条一条的操作,比较耗时。我们可以进行批量的插入操作。在进行批处理是要把自动提交关闭,改为手动提交
Statement:addBatch(String sql)
executeBatch():
PreparedStatement:addBatch():
executeBatch():
练习代码:
public class TestBatch {
@Test
public void testStatement02() {
try {
Statement stat = conn.createStatement();
conn.setAutoCommit(false);
long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
String account_idcard = 1000000000000000l + (long) ((Math.random()) * 9000000000000000l) + "";
String phone = 10000000000l + (long) ((Math.random()) * 90000000000l) + "";
String sql = "insert into account_info values(null,'" + account_idcard + "','" + 12345 + "'," + 10 + ",'" + phone + "')";
//添加批處理
stat.addBatch(sql);
if (i % 220 == 0) {
//執行一次批處理
stat.executeBatch();
conn.commit();
}
}
//將不滿220條的再次執行
stat.executeBatch();
conn.commit();
System.out.println("Statement02--1000次循環時間" + (System.currentTimeMillis() - start));
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void testPreparedStatement02() {
try {
long start = System.currentTimeMillis();
String sql = "insert into account_info values(null,?,'" + 12345 + "'," + 10 + ",?)";
PreparedStatement pr = conn.prepareStatement(sql);
conn.setAutoCommit(false);
for (int i = 0; i < 5000; i++) {
String account_idcard = 1000000000000000l + (long) ((Math.random()) * 9000000000000000l) + "";
String phone = 10000000000l + (long) ((Math.random()) * 90000000000l) + "";
pr.setString(1, account_idcard);
pr.setString(2, phone);
pr.addBatch();
if (i % 220 == 0) {
pr.executeBatch();
conn.commit();
}
}
pr.executeBatch();
conn.commit();
System.out.println("PreparedStatement02--1000次循環時間" + (System.currentTimeMillis() - start));
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void testStatement01() {
try {
Statement stat = conn.createStatement();
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
String account_idcard = 1000000000000000l + (long) ((Math.random()) * 9000000000000000l) + "";
String phone = 10000000000l + (long) ((Math.random()) * 90000000000l) + "";
String sql = "insert into account_info values(null,'" + account_idcard + "','" + 12345 + "'," + 10 + ",'" + phone + "')";
stat.executeUpdate(sql);
}
System.out.println("Statement--1000次循環時間" + (System.currentTimeMillis() - start));
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void testPreparedStatement01() {
try {
long start = System.currentTimeMillis();
String sql = "insert into account_info values(null,?,'" + 12345 + "'," + 10 + ",?)";
PreparedStatement pr = conn.prepareStatement(sql);
conn.setAutoCommit(false);
for (int i = 0; i < 10000; i++) {
String account_idcard = 1000000000000000l + (long) ((Math.random()) * 9000000000000000l) + "";
String phone = 10000000000l + (long) ((Math.random()) * 90000000000l) + "";
pr.setString(1, account_idcard);
pr.setString(2, phone);
pr.executeUpdate();
}
conn.commit();
System.out.println("PreparedStatement--1000次循環時間" + (System.currentTimeMillis() - start));
} catch (SQLException e) {
e.printStackTrace();
}
}
private Connection conn;
@Before
public void connectionDatabase() {
try {
conn = DBUtil.getConnection();
} catch (Exception e) {
}
}
}