欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解JDBC使用

 更新時(shí)間:2017年05月02日 14:57:33   作者:五月的倉(cāng)頡  
JDBC(Java Database Connectivity),即Java數(shù)據(jù)庫(kù)連接,是一種用于執(zhí)行SQL語句的Java API,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供同一訪問,它由一組用Java語言編寫的類和接口組成。

什么是JDBC

JDBC(Java Database Connectivity),即Java數(shù)據(jù)庫(kù)連接,是一種用于執(zhí)行SQL語句的Java API,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供同一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準(zhǔn),根據(jù)這種基準(zhǔn)可以構(gòu)建更高級(jí)的工具和接口,使數(shù)據(jù)庫(kù)開發(fā)人員能夠編寫數(shù)據(jù)庫(kù)應(yīng)用程序??偠灾?,JDBC做了三件事:

1、與數(shù)據(jù)庫(kù)建立連接

2、發(fā)送操作數(shù)據(jù)庫(kù)的語句

3、處理結(jié)果

JDBC簡(jiǎn)單示例

下面的代碼演示了如何利用JDBC從數(shù)據(jù)庫(kù)中查詢?nèi)舾蓷l符合要求的數(shù)據(jù)出來,使用的數(shù)據(jù)庫(kù)是MySql。

1、建立一個(gè)數(shù)據(jù)庫(kù)和一張表,我的習(xí)慣是在CLASSPATH底下建立一個(gè).sql的文件用于存放sql語句

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ì)講了,只需要記?。?strong>從設(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出來,而不會(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只是為了用來從里面讀一個(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è)工具類,用來寫各種方法,專門和數(shù)據(jù)庫(kù)進(jìn)行交互。這種工具類最好搞成單例的,這樣就不用每次去new出來了(實(shí)際上new出來也沒看出來會(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 = new ArrayList<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語句的時(shí)候用了"?"占位符,當(dāng)然有美化代碼的因素,不用占位符就要在括號(hào)里寫"+"來拼接參數(shù),如果要拼接的參數(shù)一多,代碼肯定不好看,可讀性不強(qiáng)。但是除了這個(gè)原因,還有另外一個(gè)重要的原因,就是避免一個(gè)安全問題。假設(shè)我們不用占位符寫sql語句,那"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ù),但是問題來了,如果我這么調(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語句就知道了:

select * from student where studentName = '' or '1' = '1'

'1'='1'永遠(yuǎn)成立,所以前面的查詢條件是什么都沒用。這種問題是有應(yīng)用場(chǎng)景的,不是隨便寫一下。Java越來越多的用在Web上,既然是Web,那么查詢的時(shí)候有一種情況就是用戶輸入一個(gè)條件,后臺(tái)獲取到查詢條件,拼接sql語句查數(shù)據(jù)庫(kù),有經(jīng)驗(yàn)的用戶完全可以輸入一個(gè)"‘'' or '1' = '1",這樣就拿到了庫(kù)里面的所有數(shù)據(jù)了。

JDBC事物

談數(shù)據(jù)庫(kù)必然離不開事物,事物簡(jiǎn)單說就是"要么一起成功,要么一起失敗"。那簡(jiǎn)單往前面的StudentManager里面寫一個(gè)插入學(xué)生信息的方法:

public void addStudent(String studentName, int studentAge, String studentPhone) throws Exception
{
  Connection connection = DBConnection.mysqlConnection;
  PreparedStatement ps = connection.prepareStatement("insert into student values(null,?,?,?)");
  ps.setString(1, studentName);
  ps.setInt(2, studentAge);
  ps.setString(3, studentPhone);
  if (ps.executeUpdate() > 0)
    System.out.println("添加學(xué)生信息成功");
  else
    System.out.println("添加學(xué)生信息失敗");  
}
public static void main(String[] args) throws Exception
{
  StudentManager.getInstance().addStudent("Betty", 17, "55555555");
}

運(yùn)行就不運(yùn)行了,反正最后結(jié)果是"添加學(xué)生信息成功",數(shù)據(jù)庫(kù)里面多了一條數(shù)據(jù)。注意一下:

1、增刪改用的是executeUpdate()方法,因?yàn)樵鰟h改認(rèn)為都是對(duì)數(shù)據(jù)庫(kù)的更新

2、查詢用的是executeQuery()方法,看名字就知道了"Query",查詢嘛

可能有人注意到一個(gè)問題,就是Java代碼在insert后并沒有對(duì)事物進(jìn)行commit,數(shù)據(jù)就添加進(jìn)數(shù)據(jù)庫(kù)了,也能查出來,這是為什么呢?因?yàn)镴DK的Connection設(shè)置了事物的自動(dòng)提交。如果在addStudent(...)方法里面這么寫:

Connection connection = DBConnection.mysqlConnection;
connection.setAutoCommit(false);

autoCommit這個(gè)屬性原來是true,JDK自然會(huì)幫助開發(fā)者自動(dòng)提交事物了。OK,如果要改成手動(dòng)提交事物的代碼,那么應(yīng)該這么寫addStudent(...)方法:

public void addStudent(String studentName, int studentAge, String studentPhone) throws Exception
{
  Connection connection = DBConnection.mysqlConnection;
  connection.setAutoCommit(false);
  PreparedStatement ps = connection.prepareStatement("insert into student values(null,?,?,?)");
  ps.setString(1, studentName);
  ps.setInt(2, studentAge);
  ps.setString(3, studentPhone);
  try
  {
    ps.executeUpdate();
    connection.commit();
  } 
  catch (Exception e)
  {
    e.printStackTrace();
    connection.rollback();
  }
}

要記得拋異常的時(shí)候利用rollback()方法回滾掉事物。

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • SpringBoot解決跨域問題小結(jié)

    SpringBoot解決跨域問題小結(jié)

    在現(xiàn)代Web應(yīng)用中,由于安全性和隱私的考慮,瀏覽器限制了從一個(gè)域向另一個(gè)域發(fā)起的跨域HTTP請(qǐng)求,Spring?Boot提供了多種方式來處理跨域請(qǐng)求,本文將介紹其中的幾種方法,感興趣的朋友一起看看吧
    2023-12-12
  • idea克隆maven項(xiàng)目的方法步驟(圖文)

    idea克隆maven項(xiàng)目的方法步驟(圖文)

    這篇文章主要介紹了idea克隆maven項(xiàng)目的方法步驟(圖文),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java生產(chǎn)1-100的隨機(jī)數(shù)簡(jiǎn)單實(shí)例(分享)

    Java生產(chǎn)1-100的隨機(jī)數(shù)簡(jiǎn)單實(shí)例(分享)

    下面小編就為大家?guī)硪黄狫ava生產(chǎn)1-100的隨機(jī)數(shù)簡(jiǎn)單實(shí)例(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • Maven坐標(biāo)和依賴的實(shí)現(xiàn)示例

    Maven坐標(biāo)和依賴的實(shí)現(xiàn)示例

    本文主要介紹了Maven坐標(biāo)和依賴的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • Spring?boot?使用QQ郵箱進(jìn)行一個(gè)驗(yàn)證登入功能

    Spring?boot?使用QQ郵箱進(jìn)行一個(gè)驗(yàn)證登入功能

    這篇文章主要介紹了Spring?boot?使用QQ郵箱進(jìn)行一個(gè)驗(yàn)證登入,主要包括qq郵箱開啟權(quán)限和創(chuàng)建發(fā)送驗(yàn)證碼的請(qǐng)求Controller,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • java設(shè)計(jì)模式--三種工廠模式詳解

    java設(shè)計(jì)模式--三種工廠模式詳解

    這篇文章主要為大家詳細(xì)介紹了Java設(shè)計(jì)模式之工廠模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能給你帶來幫助
    2021-07-07
  • Java修改Integer變量值遇到的問題及解決

    Java修改Integer變量值遇到的問題及解決

    這篇文章主要介紹了Java修改Integer變量值遇到的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java集合中的TreeMap解讀

    Java集合中的TreeMap解讀

    這篇文章主要介紹了Java集合中的TreeMap解讀,TreeMap可以傳入一個(gè)實(shí)現(xiàn)了 Comparator接口的一個(gè)匿名內(nèi)部類,匿名內(nèi)部類里面我們?nèi)匀豢梢匀ブ付ㄌ砑游覀兊逆I值對(duì)的這種排序規(guī)則,需要的朋友可以參考下
    2023-09-09
  • SpringCloud微服務(wù)之Config知識(shí)總結(jié)

    SpringCloud微服務(wù)之Config知識(shí)總結(jié)

    今天帶大家學(xué)習(xí)SpringCloud微服務(wù)中的Config的相關(guān)知識(shí),文中有非常詳細(xì)的介紹,對(duì)正在學(xué)習(xí)SpringCloud微服務(wù)的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • Java集合框架中迭代器Iterator解析

    Java集合框架中迭代器Iterator解析

    這篇文章主要為大家簡(jiǎn)單介紹了Java集合框架中迭代器Iterator的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03

最新評(píng)論