您好,登錄后才能下訂單哦!
本篇文章為大家展示了如何使用JDBC,代碼簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
什么是JDBC
JDBC(Java Database Connectivity),即Java數(shù)據(jù)庫(kù)連接,是一種用于執(zhí)行SQL語(yǔ)句的Java API,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供同一訪問,它由一組用Java語(yǔ)言編寫的類和接口組成。JDBC提供了一種基準(zhǔn),根據(jù)這種基準(zhǔn)可以構(gòu)建更高級(jí)的工具和接口,使數(shù)據(jù)庫(kù)開發(fā)人員能夠編寫數(shù)據(jù)庫(kù)應(yīng)用程序??偠灾?,JDBC做了三件事:
與數(shù)據(jù)庫(kù)建立連接
發(fā)送操作數(shù)據(jù)庫(kù)的語(yǔ)句
處理結(jié)果
JDBC簡(jiǎn)單示例
下面的代碼演示了如何利用JDBC從數(shù)據(jù)庫(kù)中查詢?nèi)舾蓷l符合要求的數(shù)據(jù)出來(lái),使用的數(shù)據(jù)庫(kù)是MySql。
1、建立一個(gè)數(shù)據(jù)庫(kù)和一張表,我的習(xí)慣是在CLASSPATH底下建立一個(gè).sql的文件用于存放sql語(yǔ)句
create database school; use school; create table student ( studentId int primary key auto_increment not null, studentName varchar(10) not null, studentAge int, studentPhone varchar(15) ) insert into student values(null,'Betty', '20', '00000000'); insert into student values(null,'Jerry', '18', '11111111'); insert into student values(null,'Betty', '21', '22222222'); insert into student values(null,'Steve', '27', '33333333'); insert into student values(null,'James', '22', '44444444'); commit;
2、建立一個(gè).properties文件用于存儲(chǔ)MySql連接的幾個(gè)屬性。為什么要建立.properties而不在代碼里面寫死,由于這個(gè)并不是Java設(shè)計(jì)模式的分類,就不細(xì)講了,只需要記?。?span>從設(shè)計(jì)的角度看,把內(nèi)容寫在配置文件中永遠(yuǎn)好過把內(nèi)容寫死在代碼中。
mysqlpackage=com.mysql.jdbc.Driver mysqlurl=jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf-8 mysqlname=root mysqlpassword=root
3、根據(jù)表字段建立實(shí)體類
public class Student { private int studentId; private String studentName; private int studentAge; private String studentPhone; public Student(int studentId, String studentName, int studentAge, String studentPhone) { this.studentId = studentId; this.studentName = studentName; this.studentAge = studentAge; this.studentPhone = studentPhone; } public int getStudentId() { return studentId; } public String getStudentName() { return studentName; } public int getStudentAge() { return studentAge; } public String getStudentPhone() { return studentPhone; } public String toString() { return "studentId = " + studentId + ", studentName = " + studentName + ", studentAge = " + studentAge + ", studentPhone = " + studentPhone; } }
4、寫一個(gè)DBConnection類專門用于向外提供數(shù)據(jù)庫(kù)連接。我這里用了MySql,所以只有一個(gè)mysqlConnection,如果還用到了Oracle,當(dāng)然還可以向外提供一個(gè)oracleConnection。把這些連接設(shè)為全局的可能有人會(huì)想是否會(huì)有線程安全問題,這是一個(gè)很好的問題。那因?yàn)槲覀冎粡腃onnection里面讀取一個(gè)PreparedStatement出來(lái),而不會(huì)去寫它,只讀不修改,是不會(huì)引發(fā)線程安全問題的。另外把Connection設(shè)置為static的保證了Connection在內(nèi)存中只有一份,不會(huì)占多大資源,每次使用完不調(diào)用close()方法去關(guān)閉它也沒事。
public class DBConnection { private static Properties properties = new Properties(); static { /** 要從CLASSPATH下取.properties文件,因此要加"/" */ InputStream is = DBConnection.class.getResourceAsStream("/db.properties"); try { properties.load(is); } catch (IOException e) { e.printStackTrace(); } } /** 這個(gè)mysqlConnection只是為了用來(lái)從里面讀一個(gè)PreparedStatement,不會(huì)往里面寫數(shù)據(jù),因此沒有線程安全問題,可以作為一個(gè)全局變量 */ public static Connection mysqlConnection = getConnection(); public static Connection getConnection() { Connection con = null; try { Class.forName((String)properties.getProperty("mysqlpackage")); con = DriverManager.getConnection((String)properties.getProperty("mysqlurl"), (String)properties.getProperty("mysqlname"), (String)properties.getProperty("mysqlpassword")); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return con; } }
5、建立一個(gè)工具類,用來(lái)寫各種方法,專門和數(shù)據(jù)庫(kù)進(jìn)行交互。這種工具類最好搞成單例的,這樣就不用每次去new出來(lái)了(實(shí)際上new出來(lái)也沒看出來(lái)會(huì)有什么好處),節(jié)省資源
package com.xrq.test11; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; public class StudentManager { private static StudentManager instance = new StudentManager(); private StudentManager() { } public static StudentManager getInstance() { return instance; } public List<Student> querySomeStudents(String studentName) throws Exception { List<Student> studentList = new ArrayList<Student>(); Connection connection = DBConnection.mysqlConnection; PreparedStatement ps = connection.prepareStatement("select * from student where studentName = ?"); ps.setString(1, studentName); ResultSet rs = ps.executeQuery(); Student student = null; while (rs.next()) { student = new Student(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getString(4)); studentList.add(student); } ps.close(); rs.close(); return studentList; } }
6、寫個(gè)main函數(shù)去調(diào)用一下
List<Student> studentList = StudentManager.getInstance().querySomeStudents("Betty"); for (Student student : studentList) { System.out.println(student); }
7、看一下運(yùn)行結(jié)果,和數(shù)據(jù)庫(kù)里面的一樣,成功
studentId = 1, studentName = Betty, studentAge = 20, studentPhone = 00000000 studentId = 3, studentName = Betty, studentAge = 21, studentPhone = 22222222
為什么要使用占位符"?"
看一下第5點(diǎn),大家一定注意到了,寫sql語(yǔ)句的時(shí)候用了"?"占位符,當(dāng)然有美化代碼的因素,不用占位符就要在括號(hào)里寫"+"來(lái)拼接參數(shù),如果要拼接的參數(shù)一多,代碼肯定不好看,可讀性不強(qiáng)。但是除了這個(gè)原因,還有另外一個(gè)重要的原因,就是避免一個(gè)安全問題。假設(shè)我們不用占位符寫sql語(yǔ)句,那"querySomeStudents(String name) throws Exception"方法就要這么寫:
public List<Student> querySomeStudents(String studentName) throws Exception { List<Student> studentList = new ArrayList<Student>(); Connection connection = DBConnection.mysqlConnection; PreparedStatement ps = connection.prepareStatement("select * from student where studentName = '" + studentName + "'"); ResultSet rs = ps.executeQuery(); Student student = null; while (rs.next()) { student = new Student(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getString(4)); studentList.add(student); } ps.close(); rs.close(); return studentList; }
上面的main函數(shù)一樣可以獲取到兩條數(shù)據(jù),但是問題來(lái)了,如果我這么調(diào)用呢:
public static void main(String[] args) throws Exception { List<Student> studentList = new ArrayList<Student>(); studentList = StudentManager.getInstance().querySomeStudents("' or '1' = '1"); for (Student student : studentList) System.out.println(student); }
看下運(yùn)行結(jié)果:
studentId = 1, studentName = Betty, studentAge = 20, studentPhone = 00000000 studentId = 2, studentName = Jerry, studentAge = 18, studentPhone = 11111111 studentId = 3, studentName = Betty, studentAge = 21, studentPhone = 22222222 studentId = 4, studentName = Steve, studentAge = 27, studentPhone = 33333333 studentId = 5, studentName = James, studentAge = 22, studentPhone = 44444444
為什么?看下拼接之后的sql語(yǔ)句就知道了:
select * from student where studentName = '' or '1' = '1'
'1'='1'永遠(yuǎn)成立,所以前面的查詢條件是什么都沒用。這種問題是有應(yīng)用場(chǎng)景的,不是隨便寫一下。Java越來(lái)越多的用在Web上,既然是Web,那么查詢的時(shí)候有一種情況就是用戶輸入一個(gè)條件,后臺(tái)獲取到查詢條件,拼接sql語(yǔ)句查數(shù)據(jù)庫(kù),有經(jīng)驗(yàn)的用戶完全可以輸入一個(gè)"‘'' or '1' = '1",這樣就拿到了庫(kù)里面的所有數(shù)據(jù)了。
Statement 和 PreparedStatement之間的關(guān)系和區(qū)別.
關(guān)系:PreparedStatement繼承自Statement,都是接口
區(qū)別:PreparedStatement可以使用占位符,是預(yù)編譯的,批處理比Statement效率高
JDBC事務(wù)
什么是事務(wù):事務(wù)就是操作一組數(shù)據(jù)庫(kù)的操作集合。如果一組處理步驟或者全部發(fā)生或者一步也不執(zhí)行,我們稱改組處理為一個(gè)事務(wù)。
事務(wù)的基本特性:原子性,一致性,隔離性,持久性。
原子性: 原子性是指事務(wù)是一個(gè)不可再分割的工作單元,事務(wù)中的操作要么都發(fā)生,要么都不發(fā)生。
一致性:一致性是指在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫(kù)的完整性約束沒有被破壞。這是說(shuō)數(shù)據(jù)庫(kù)事務(wù)不能破壞關(guān)系數(shù)據(jù)的完整性以及業(yè)務(wù)邏輯上的一致性。
如A給B轉(zhuǎn)賬,不論轉(zhuǎn)賬的事務(wù)操作是否成功,其兩者的存款總額不變。
隔離性:多個(gè)事務(wù)并發(fā)訪問時(shí),事務(wù)之間是隔離的,一個(gè)事務(wù)不應(yīng)該影響其它事務(wù)運(yùn)行效果。
在并發(fā)環(huán)境中,當(dāng)不同的事務(wù)同時(shí)操縱相同的數(shù)據(jù)時(shí),每個(gè)事務(wù)都有各自的完整數(shù)據(jù)空間。由并發(fā)事務(wù)所做的修改必須與任何其他并發(fā)事務(wù)所做的修改隔離。事務(wù)查看數(shù)據(jù)更新時(shí),數(shù)據(jù)所處的狀態(tài)要么是另一事務(wù)修改它之前的狀態(tài),要么是另一事務(wù)修改它之后的狀態(tài),事務(wù)不會(huì)查看到中間狀態(tài)的數(shù)據(jù)。
事務(wù)最復(fù)雜問題都是由事務(wù)隔離性引起的。完全的隔離性是不現(xiàn)實(shí)的,完全的隔離性要求數(shù)據(jù)庫(kù)同一時(shí)間只執(zhí)行一條事務(wù),這樣會(huì)嚴(yán)重影響性能。
持久性:意味著在事務(wù)完成以后,該事務(wù)所對(duì)數(shù)據(jù)庫(kù)所作的更改便持久的保存在數(shù)據(jù)庫(kù)之中,并不會(huì)被回滾。
上述內(nèi)容就是如何使用JDBC,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。