Berbagi teknologi

JavaWeb (3: JDBC dan MVC)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

JavaWeb (1: Pengetahuan dasar dan konstruksi lingkungan)ikon-default.png?t=N7T8https://blog.csdn.net/xpy2428507302/artikel/detail/140365130?spm=1001.2014.3001.5501JavaWeb (2: Servlet dan Jsp, pendengar dan filter)ikon-default.png?t=N7T8https://blog.csdn.net/xpy2428507302/artikel/detail/140365159?spm=1001.2014.3001.5501

Daftar isi

10.JDBC

1 Ikhtisar

2.Tulis program JDBC

3. Analisis rinci

(1) Url basis data

(2) Kelas koneksi

(3) Kelas pernyataan

(4) kelas HasilSet

(5) Melepaskan sumber daya

4. Masalah injeksi SQL

5.transaksi JDBC

6. Kelas alat JDBC

7. Kumpulan koneksi database

(1 Ikhtisar

(2) Gunakan

8.DBUtil

11. Arsitektur tiga tingkat MVC

1. Perkenalan

2. arsitektur tiga tingkat mvc


10.JDBC

1 Ikhtisar

JDBC (Java DataBase Connectivity): Teknologi koneksi database Java

JDBC adalah sistem manajemen yang tidak bergantung pada database tertentu dan antarmuka publik untuk akses dan operasi database SQL universal.

Mendefinisikan seperangkat standar untuk menyediakan cara terpadu untuk mengakses database yang berbeda.

JDBC adalah API aplikasi untuk akses database, terdiri dari sekumpulan kelas dan antarmuka yang ditulis dalam bahasa Java.

Termasuk dua level:

① API berorientasi aplikasi untuk dipanggil oleh pemrogram.

② API berorientasi basis data bagi produsen untuk mengembangkan driver basis data.

Untuk menghubungkan database yang berbeda dengan JDBC, Anda hanya perlu memuat paket driver database yang berbeda, dan Anda tidak perlu khawatir tentang perbedaan bahasa pengoperasian database.

2.Tulis program JDBC

① Buat tabel database

  1. CREATE TABLE users(
  2. id INT PRIMARY KEY,
  3. `name` VARCHAR(40),
  4. `password` VARCHAR(40),
  5. email VARCHAR(60),
  6. birthday DATE
  7. );
  8. INSERT INTO users(id,`name`,`password`,email,birthday)
  9. VALUES(1,'张三','123456','[email protected]','2000-01-01');
  10. INSERT INTO users(id,`name`,`password`,email,birthday)
  11. VALUES(2,'李四','123456','[email protected]','2000-01-01');
  12. INSERT INTO users(id,`name`,`password`,email,birthday)
  13. VALUES(3,'王五','123456','[email protected]','2000-01-01');
  14. SELECT * FROM users;

② Impor dependensi basis data

  1. <!--mysql的驱动-->
  2. <dependency>
  3. <groupId>mysql</groupId>
  4. <artifactId>mysql-connector-java</artifactId>
  5. <version>8.0.31</version>
  6. </dependency>

③ Penggunaan JDBC:

Ⅰ.Muat driver database (jembatan antara program java dan database)

Ⅱ. Obtain Connection, koneksi antara program java dengan database

Ⅲ. Buat objek Pernyataan yang mengirimkan SQL ke database, dihasilkan oleh Connection

Ⅳ. Tulis pernyataan SQL (tulis SQL yang berbeda sesuai dengan bisnisnya)

Ⅴ.Jalankan SQL (jika Anda ingin menerima nilai kembalian, buat objek ResultSet untuk menyimpan hasil kueri setelah Pernyataan dijalankan)

  1. public class JDBCTest {
  2. public static void main(String[] args) throws Exception {
  3. //配置信息
  4. //要连接的数据库URL(解决中文乱码问题:useUnicode=true&characterEncoding=utf8&useSSL=true)
  5. String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  6. //连接的数据库时使用的用户名
  7. String username = "root";
  8. //连接的数据库时使用的密码
  9. String password = "123456";
  10. Connection conn = null;
  11. Statement st = null;
  12. ResultSet rs = null;
  13. try {
  14. //1.加载驱动
  15. Class.forName("com.mysql.cj.jdbc.Driver");
  16. //2.获取与数据库的链接
  17. conn = DriverManager.getConnection(url, username, password);
  18. //3.获取用于向数据库发送sql语句的statement对象
  19. st = conn.createStatement();
  20. String sql = "select id,name,password,email,birthday from users";
  21. //4.向数据库发sql,并获取代表结果集的resultset对象
  22. //查:executeQuery 增删改:executeUpdate
  23. rs = st.executeQuery(sql);
  24. //5.取出结果集的数据
  25. while (rs.next()) {
  26. System.out.println("id=" + rs.getInt("id"));
  27. System.out.println("name=" + rs.getString("name"));
  28. System.out.println("password=" + rs.getString("password"));
  29. System.out.println("email=" + rs.getString("email"));
  30. System.out.println("birthday=" + rs.getDate("birthday"));
  31. }
  32. } catch (ClassNotFoundException e) {
  33. e.printStackTrace();
  34. } catch (SQLException e) {
  35. e.printStackTrace();
  36. } finally {
  37. try {
  38. //6.关闭链接,释放资源(先开后关)
  39. rs.close();
  40. st.close();
  41. conn.close();
  42. } catch (SQLException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. }

3. Analisis rinci

(1) Url basis data

jdbc:mysql://host lokal:3306/xxx

jdbcprotokol
mysqlsub-protokol
tuan rumah lokal:3306tuan rumah:pelabuhan
xxxbasis data

Cara menulis alamat URL database yang umum digunakan:

  • Penulisan Oracle: jdbc:Oracle:thin:@hosting lokal:1521:xxx
  • Konfigurasi SqlServer: jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=xxx
  • Metode penulisan MySql: jdbc:mysql://localhost:3306/xxx

(2) Kelas koneksi

Koneksi digunakan untuk mewakili link database, dan Koleksi adalah objek terpenting dalam pemrograman database.

Semua interaksi antara klien dan database diselesaikan melalui objek koneksi., metode umum dari objek ini:

buatPernyataan()Buat objek pernyataan yang mengirimkan sql ke database
persiapkanPernyataan(sql)Buat objek PrepareSatement yang mengirimkan sql yang telah dikompilasi ke database
setAutoCommit(boolean autoCommit)Atur apakah transaksi dilakukan secara otomatis
melakukan()Kirim transaksi pada tautan
kembalikan()Kembalikan transaksi pada tautan ini

(3) Kelas pernyataan

Objek pernyataan digunakan untuk mengirim pernyataan SQL ke database. Metode umum objek Pernyataan:

eksekusiQuery(String sql)Digunakan untuk mengirim pernyataan kueri ke data dan mengembalikan kumpulan hasil ResultSet
eksekusiPembaruan(String sql)Digunakan untuk mengirim pernyataan penyisipan, pembaruan, atau penghapusan ke database dan mengembalikan jumlah baris yang diperbarui dalam database
eksekusi(String sql)Digunakan untuk mengirim pernyataan sql sewenang-wenang ke database
tambahkanBatch(String sql)Masukkan beberapa pernyataan sql ke dalam satu batch
eksekusiBatch()Kirim sekumpulan pernyataan sql ke database untuk dieksekusi

Melihat:

Untuk meningkatkan efisiensi pengoperasian, metode eksekusi umumnya tidak digunakan secara langsung.

Sebagai gantinya, gunakanlah sesuai dengan: mengeksekusiQuery untuk kueri; mengeksekusiUpdate untuk penambahan, penghapusan, dan modifikasi.

(4) kelas HasilSet

ResultSet digunakan untuk mewakili hasil eksekusi pernyataan Sql.

Kumpulan hasil Saat merangkum kumpulan hasil eksekusi, gunakanmirip dengan tabelJalan

Objek ResultSet mempertahankan kursor yang menunjuk ke baris data tabel.Awalnya, kursor berada sebelum baris pertama

Memanggil metode ResultSet.next() dapat membuat kursor menunjuk ke baris data tertentu, dan memanggil metode getxxx untuk mendapatkan data baris tersebut.

① Dapatkan semua jenis data

getObject(int indeks)

Dapatkan objek Object sesuai dengan jumlah kolom yang ditentukan

getObject(string namakolom)Dapatkan objek Object sesuai dengan nama atribut yang ditentukan

② Mendapatkan data dengan tipe tertentu, seperti mendapatkan tipe String

dapatkanString(int indeks)

Dapatkan objek String berdasarkan jumlah kolom yang ditentukan

getString(String namakolom)Dapatkan objek String sesuai dengan nama atribut yang ditentukan

③ Cara menggulir kumpulan hasil: 

Berikutnya()pindah ke baris berikutnya
Sebelumnya()berpindah ke baris sebelumnya
absolut(int baris)Pindah ke baris yang ditentukan
sebelumPertama()Pindahkan bagian depan resultSet
setelahTerakhir()Pindah ke akhir resultSet

(5) Melepaskan sumber daya

Setelah program Jdbc selesai dijalankan, ingatlah untuk melepaskan objek yang dibuat oleh program untuk berinteraksi dengan database selama proses berjalan.

Objek-objek ini biasanya adalah objek ResultSet, Statement, dan Connection.

Khususnya objek Connection, merupakan resource yang sangat langka dan harus segera dilepaskan setelah digunakan.

Jika Koneksi tidak dapat ditutup dengan cepat dan benar, hal ini dapat dengan mudah menyebabkan downtime sistem.

Untuk memastikan kode rilis sumber daya dapat berjalan, kode rilis sumber daya juga harus ditempatkan di pernyataan akhirnya.

4. Masalah injeksi SQL

Ada dua masalah saat menggunakan Pernyataan untuk pengembangan:

① Senar senar harus sering disambung, dan tingkat kesalahannya tinggi

  1. String username = "zhangsan";
  2. String password = "123";
  3. String sql = "select * from users where name='"+username+"' and password='"+password+"'";
  4. ResultSet rs = st.executeQuery(sql);

② Ada potensi risiko injeksi SQL

Injeksi SQL: Memasukkan pernyataan SQL ilegal ke dalam data yang dimasukkan oleh pengguna, menggunakan teknik cerdas untuk menyambung string, menyebabkan korsleting SQL, sehingga mencuri data database.

  1. public class SQLTest {
  2. public static void main(String[] args) throws Exception {
  3. // 正常登陆sql:select * from users where name='张三' and password ='123456'
  4. //login("张三","123456");
  5. // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
  6. login("", "123456' or '1'='1");
  7. }
  8. public static void login(String username, String password) throws Exception {
  9. String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  10. String dbUsername = "root";
  11. String dbPassword = "123456";
  12. //1.加载驱动
  13. Class.forName("com.mysql.cj.jdbc.Driver");
  14. //2.获取与数据库的链接
  15. Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
  16. //3.获取用于向数据库发送sql语句的statement
  17. Statement st = conn.createStatement();
  18. String sql = "select * from users where name='" + username + "' and password='" + password + "'";
  19. System.out.println(sql);
  20. //4.向数据库发sql,并获取代表结果集的rs
  21. ResultSet rs = st.executeQuery(sql);
  22. if (rs.next()) {
  23. System.out.println("登录成功");
  24. } else {
  25. System.out.println("登录失败");
  26. }
  27. //6.关闭链接,释放资源
  28. rs.close();
  29. st.close();
  30. conn.close();
  31. }
  32. }

hasil operasi:

Melihat:

Prioritas dan dalam pernyataan SQL lebih besar dari atau, sehingga SQL yang dieksekusi setara dengan pilih * dari pengguna di mana '1' = '1';


Larutan:Gunakan PreparedStatement, subkelas Pernyataan, yang menyediakan fungsi placeholder SQL.

Tidak perlu menyambung string, dan data yang dimasukkan oleh pengguna akan terdeteksi sepenuhnya, sehingga lebih aman.

  1. public class PSTest {
  2. public static void main(String[] args) throws Exception {
  3. // 正常登陆sql:select * from users where name='张三' and password ='123456'
  4. //login("张三","123456");
  5. // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
  6. login("", "123456' or '1'='1");
  7. }
  8. public static void login(String username, String password) throws Exception {
  9. String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  10. String dbUsername = "root";
  11. String dbPassword = "123456";
  12. Class.forName("com.mysql.cj.jdbc.Driver");
  13. Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
  14. //获取用于向数据库发送预编译sql语句的prepareStatement
  15. String sql = "select * from users where name = ? and password = ?";
  16. System.out.println(sql);
  17. PreparedStatement ps = conn.prepareStatement(sql);
  18. //给占位符 ? 填充数据
  19. ps.setString(1, username);
  20. ps.setString(2, password);
  21. ResultSet rs = ps.executeQuery();
  22. if (rs.next()) {
  23. System.out.println("登录成功");
  24. } else {
  25. System.out.println("登录失败");
  26. }
  27. rs.close();
  28. ps.close();
  29. conn.close();
  30. }
  31. }

hasil operasi:

5.transaksi JDBC

Suatu transaksi mengacu pada serangkaian operasi logis, baik semuanya berhasil atau semuanya gagal (prinsip ACID).

Ketika program Jdbc memperoleh objek Connection dari database, secara default objek Connection akan secara otomatis mengirimkan transaksi ke database.

Jika Anda ingin menonaktifkan metode pengiriman default ini dan mengizinkan beberapa SQL dieksekusi dalam satu transaksi, Anda dapat menggunakan pernyataan transaksi kontrol JDBC berikut.

Koneksi.setAutoCommit(salah);

memulai transaksi
Koneksi.rollback();Transaksi pengembalian
Koneksi.komit();melakukan transaksi

① Buat tabel akun

  1. /*创建账户表*/
  2. CREATE TABLE account(
  3. id INT PRIMARY KEY AUTO_INCREMENT,
  4. NAME VARCHAR(40),
  5. money DECIMAL(9,2)
  6. );
  7. /*插入测试数据*/
  8. insert into account(name,money) values('A',1000);
  9. insert into account(name,money) values('B',1000);
  10. insert into account(name,money) values('C',1000);

② Simulasikan skenario bisnis ketika transfer berhasil

  1. //失败后让数据库自动回滚事务
  2. public class Demo {
  3. public static void main(String[] args) {
  4. String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  5. String username = "root";
  6. String password = "123456";
  7. Connection conn = null;
  8. try {
  9. Class.forName("com.mysql.cj.jdbc.Driver");
  10. conn = DriverManager.getConnection(url, username, password);
  11. //通知数据库开启事务,false表示开启
  12. conn.setAutoCommit(false);
  13. String sql1 = "update account set money=money-100 where name = 'A' ";
  14. conn.prepareStatement(sql1).executeUpdate();
  15. //模拟执行完SQL1之后程序出现了异常而导致后面的SQL无法正常执行,事务也无法正常提交
  16. int x = 1/0;
  17. String sql2 = "update account set money=money+100 where name = 'B' ";
  18. conn.prepareStatement(sql2)executeUpdate();
  19. //sql1 和 sql2都顺利执行,就提交事务
  20. conn.commit();
  21. System.out.println("成功!!!");
  22. } catch (Exception e) {
  23. //出现异常,通知数据库回滚事务
  24. conn.rollback();
  25. e.printStackTrace();
  26. } finally {
  27. conn.close();
  28. }
  29. }
  30. }

6. Kelas alat JDBC

Dalam permintaan yang berbeda, Anda perlu terhubung ke database dan melepaskan sumber daya setiap kali, dan banyak kode berulang akan ditulis.

Enkapsulasi operasi persiapan dan pelepasan koneksi database ke dalam kelas alat, dan panggil secara langsung saat menggunakannya untuk menghindari penulisan kode berulang.

  1. public class JdbcUtil {
  2. private static Connection connection;
  3. private static String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
  4. private static String username = "root";
  5. private static String password = "123456";
  6. //驱动(类)只需要加载一次,放静态代码块即可
  7. static {
  8. try {
  9. //加载数据库驱动
  10. Class.forName("com.mysql.cj.jdbc.Driver");
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. // 获取数据库连接对象
  16. public static Connection getConnection() throws SQLException {
  17. return DriverManager.getConnection(url, username, password);
  18. }
  19. // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
  20. public static void release(Connection conn, Statement st, ResultSet rs) {
  21. try {
  22. if (rs != null) {
  23. rs.close();
  24. }
  25. if (st != null) {
  26. st.close();
  27. }
  28. if (conn != null) {
  29. conn.close();
  30. }
  31. } catch (SQLException e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. }

Kasus panggilan, seperti: tambahkan pengguna

  1. public void add(String name, String password) {
  2. Connection conn = null;
  3. PreparedStatement ps = null;
  4. try {
  5. conn = JdbcUtil.getConnection();
  6. String sql = "insert into users(name,password) values(?,?)";
  7. ps = conn.prepareStatement(sql);
  8. ps.setString(1, name);
  9. ps.setString(2, password);
  10. ps.executeUpdate();
  11. } catch (SQLException e) {
  12. e.printStackTrace();
  13. } finally {
  14. JdbcUtil.release(conn, ps, null);
  15. }
  16. }

7. Kumpulan koneksi database

(1 Ikhtisar

Proses pengembangan JDBC:

Ⅰ. Muat driver database (hanya perlu dimuat satu kali)

Ⅱ. Membangun koneksi database (Koneksi)

Ⅲ. Buat objek Pernyataan yang mengirimkan SQL ke database, dihasilkan oleh Connection

Ⅳ. Menulis pernyataan SQL

Ⅴ.Jalankan SQL (Query--&gt;objek ResultSet menerima kumpulan hasil)

Ⅵ. Tutup koneksi dan lepaskan sumber daya


Objek koneksi database diperoleh melalui DriverManager. Setiap kali diperoleh, Anda perlu mendaftar ke database untuk mendapatkan koneksi dan memverifikasi nama pengguna dan kata sandi.

Pengguna perlu mendapatkan tautan dari database untuk setiap permintaan, dan membuat koneksi ke database biasanya menghabiskan sumber daya yang relatif besar dan membutuhkan waktu lama untuk membuatnya.

Setiap kali pernyataan SQL dijalankan, koneksi terputus, yang akan menyebabkan pemborosan sumber daya dan sumber daya koneksi database tidak digunakan kembali dengan baik.

Dengan asumsi bahwa situs web menerima 100.000 kunjungan setiap hari, server database perlu membuat 100.000 koneksi, yang merupakan pemborosan sumber daya database dan dapat dengan mudah menyebabkan kelebihan memori server database dan perluasan mesin.

Solusi: Kumpulan koneksi database

Ide dasar kumpulan koneksi database:

Buat kumpulan buffer untuk database dan masukkan sejumlah objek koneksi ke dalam kumpulan buffer terlebih dahulu.

Saat ingin mendapatkan koneksi database, Anda hanya perlu mengambil objek dari buffer pool.

Setelah digunakan, masukkan kembali ke dalam kumpulan buffer untuk permintaan berikutnya, sehingga sumber daya dapat digunakan kembali tanpa perlu pembuatan berulang kali.

Ketika tidak ada objek koneksi yang menganggur di kumpulan koneksi database, permintaan baru akan masuk ke antrian tunggu dan menunggu thread lain melepaskan koneksi.

(2) Gunakan

Kumpulan koneksi database JDBC diselesaikan menggunakan antarmuka javax.sql.DataSource. DataSource adalah antarmuka resmi yang disediakan oleh Java.

Saat menggunakannya, pengembang tidak perlu mengimplementasikan antarmukanya sendiri dan dapat menggunakan alat pihak ketiga.

C3P0 adalah implementasi pihak ketiga yang umum digunakan. Dalam pengembangan sebenarnya, C3P0 dapat digunakan secara langsung untuk menyelesaikan pengoperasian kumpulan koneksi database.

Langkah-langkah penggunaan:

① Impor dependensi di pom.xml

  1. <dependency>
  2. <groupId>com.mchange</groupId>
  3. <artifactId>c3p0</artifactId>
  4. <version>0.9.5.2</version>
  5. </dependency>

② Tulis kode

  1. public class DataSourceTest {
  2. public static void main(String[] args) {
  3. try {
  4. //创建C3P0数据库连接池
  5. ComboPooledDataSource dataSource=new ComboPooledDataSource();
  6. dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
  7. dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8");
  8. dataSource.setUser("root");
  9. dataSource.setPassword("123456");
  10. //设置初始化连接个数
  11. dataSource.setInitialPoolSize(5);
  12. //设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限)
  13. dataSource.setMaxPoolSize(20);
  14. //当连接对象不够时,再次申请的连接对象个数
  15. dataSource.setAcquireIncrement(5);
  16. //设置最小连接数(当连接池中剩余2个连接对象时,就去申请 --> 提前做准备)
  17. dataSource.setMinPoolSize(2);
  18. Connection conn=dataSource.getConnection();
  19. //SQL操作...
  20. //将连接还回到数据库连接池中
  21. conn.close();
  22. } catch (PropertyVetoException e) {
  23. e.printStackTrace();
  24. } catch (SQLException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }

Melihat:

Koneksi diperoleh melalui metode tradisional: com.mysql.cj.jdbc.ConnectionImpl@3c153a1

Koneksi diperoleh oleh C3P0: com.mchange.v2.c3p0.impl.NewProxyConnection@6156496

Jadi,Walaupun semuanya memanggil metode close, kelas implementasinya berbeda, sehingga penulisan ulang metodenya juga berbeda. Ini adalah polimorfisme antarmuka.

Metode close di C3P0 tidak secara langsung menghancurkan sumber daya koneksi, namun mengembalikan koneksi ke kumpulan koneksi database.


Metode pengaturan parameter kumpulan koneksi database di atas ditulis langsung di program Java.

Ini diadopsiKode kerasJalan,Setiap kali Anda mengubah konfigurasiPerlu dikompilasi ulang, menghasilkan file kelas baru, efisiensinya terlalu rendah

Dalam pengembangan sebenarnya, informasi konfigurasi C3P0 didefinisikan dalam file xml, dan program java hanya perlu memuat file konfigurasi untuk menyelesaikan operasi inisialisasi kumpulan koneksi database.

Selanjutnya Anda hanya perlu memodifikasi konfigurasi dan memodifikasi konfigurasi di xml tanpa melakukan kompilasi ulang.

Langkah-langkah penggunaan:

① Di direktori sumber daya, buat file baru bernama c3p0-config.xml

② Isi informasi konfigurasi di c3p0-config.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <c3p0-config>
  3. <!--配置连接池mysql-->
  4. <named-config name="C3P0Test">
  5. <!-- 指定连接数据源的基本属性 -->
  6. <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
  7. <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc?useUnicode=true&amp;characterEncoding=utf8</property>
  8. <property name="user">root</property>
  9. <property name="password">123456</property>
  10. <!-- 设置初始化连接个数 -->
  11. <property name="initialPoolSize">5</property>
  12. <!-- 设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限) -->
  13. <property name="maxPoolSize">20</property>
  14. <!-- 当连接对象不够时,再次申请的连接对象个数 -->
  15. <property name="acquireIncrement">5</property>
  16. <!-- 设置最小连接数(当连接池中剩余2个连接对象时,就去申请 -> 提前做准备) -->
  17. <property name="minPoolSize">2</property>
  18. </named-config>
  19. </c3p0-config>

③Tulis program Java

  1. public class DataSourceTest {
  2. public static void main(String[] args) {
  3. try {
  4. //创建C3P0数据库连接池
  5. ComboPooledDataSource dataSource=new ComboPooledDataSource("C3P0Test");
  6. Connection conn=dataSource.getConnection();
  7. System.out.println(conn);
  8. //将连接还回到数据库连接池中
  9. conn.close();
  10. }catch (SQLException e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. }

Melihat:

① Parameter dalam metode konstruksi ComboPooledDataSource adalah nilai atribut nama dari tag bernama-config yang dikonfigurasi di c3p0-config.xml.

② Saat ini, kelas alat JDBC dapat dimodifikasi sebagai:

  1. public class JdbcUtil {
  2. private static DataSource dataSource;
  3. static {
  4. dataSource = new ComboPooledDataSource("C3P0Test");
  5. }
  6. // 获取数据库连接对象
  7. public static Connection getConnection() throws SQLException {
  8. Connection conn = null;
  9. try {
  10. conn = dataSource.getConnection();
  11. } catch (SQLException e) {
  12. e.printStackTrace();
  13. }
  14. return conn;
  15. }
  16. // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
  17. public static void release(Connection conn, Statement st, ResultSet rs) {
  18. try {
  19. if (rs != null) {
  20. rs.close();
  21. }
  22. if (st != null) {
  23. st.close();
  24. }
  25. if (conn != null) {
  26. conn.close();
  27. }
  28. } catch (SQLException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }

8.DBUtil

  1. public static Student findById(Integer idx) {
  2. Connection conn = null;
  3. PreparedStatement st = null;
  4. ResultSet rs = null;
  5. Student stu = null;
  6. try {
  7. conn = JdbcUtil.getConnection();
  8. String sql = "select * from student where id = ?";
  9. PreparedStatement ps = conn.prepareStatement(sql);
  10. //给占位符 ? 填充数据
  11. ps.setInt(1, idx);
  12. rs = ps.executeQuery();
  13. //取出结果集的数据
  14. while (rs.next()) {
  15. Integer id = rs.getInt(1);
  16. String name = rs.getString(2);
  17. Double score = rs.getDouble(3);
  18. Date birthday = rs.getDate(4);
  19. stu = new Student(id, name, score, birthday);
  20. }
  21. } catch (SQLException e) {
  22. e.printStackTrace();
  23. } finally {
  24. try {
  25. //关闭链接,释放资源
  26. rs.close();
  27. st.close();
  28. conn.close();
  29. } catch (SQLException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. return stu;
  34. }

Dalam kode di atas, operasi pengisian placeholder dengan data dan mengekstraksi data dari kumpulan hasil terlalu rumit.

Jika ada 100 atribut dalam tabel Siswa, maka kita harus menulis 100 baris dalam perulangan while untuk mengambil datanya, dan mungkin juga diperlukan banyak baris untuk mengisi placeholder.


Larutan:DBUtils dapat membantu pengembang menyelesaikan enkapsulasi data (pemetaan kumpulan hasil ke objek Java).

Langkah-langkah penggunaan:

① Impor dependensi di pom.xml

  1. <dependency>
  2. <groupId>commons-dbutils</groupId>
  3. <artifactId>commons-dbutils</artifactId>
  4. <version>1.6</version>
  5. </dependency>

② Tulis kode

  1. public static Student findById(Integer idx) {
  2. Connection conn = null;
  3. Student stu = null;
  4. try {
  5. conn = JdbcUtil.getConnection();
  6. String sql = "select * from student where id = ?";
  7. //使用DBUtils
  8. QueryRunner qr = new QueryRunner();
  9. stu = qr.query(conn, sql, new BeanHandler<>(Student.class), idx);
  10. } catch (SQLException e) {
  11. e.printStackTrace();
  12. } finally {
  13. try {
  14. //关闭链接,释放资源
  15. conn.close();
  16. } catch (SQLException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. return stu;
  21. }

Pada titik ini, mengisi placeholder dan mengeluarkan kumpulan hasil dapat dilakukan dengan dua baris kode.

rincian:

① Metode kueri harus memasukkan 4 parameter:

Objek koneksi

pernyataan SQL

Objek kelas implementasi antarmuka ResultSetHandler (tipe objek yang dikonversi harus: Student.class)

Parameter untuk mengisi placeholder

② Antarmuka ResultSetHandler digunakan untuk memproses kumpulan hasil. Ia dapat mengubah kumpulan hasil yang ditanyakan menjadi objek Java berikut.

Penangan KacangPetakan hasil yang ditetapkan ke dalam objek Java (seperti objek Siswa)
Penanganan Daftar Kacang Petakan kumpulan hasil ke dalam kumpulan Daftar (seperti: Daftar<Student > )
Penangan Peta

Petakan kumpulan hasil ke dalam objek koleksi Peta

(yaitu: Peta<String,Object> kunci: nama atribut; nilai: nilai atribut)

PenanganDaftarPeta Petakan kumpulan hasil ke dalam koleksi MapList (yaitu: List <Map<<String,Object> &gt;)

③ Parameter untuk mengisi placeholder adalah parameter variabel, sehingga sejumlah parameter dapat diteruskan untuk memenuhi kebutuhan pengguna yang berbeda.

④ Kelas objek yang dikonversi (kelas Siswa) harus memiliki konstruktor tanpa parameter, jika tidak, program akan melaporkan kesalahan.

alasan:Lapisan bawah menemukan kelas ini melalui Student.class, dan kemudian melaluimekanisme refleksiTemukan konstruktor tanpa parameter dari kelas ini dan buat objeknya.

⑤ Nama atribut pada kelas harus sama persis dengan nama field pada tabel database.

Karena setelah objek dibuat, ketika memberikan nilai pada properti objek berdasarkan kumpulan hasil, pencarian dan penugasan dilakukan berdasarkan namanya.

11. Arsitektur tiga tingkat MVC

Apa itu MVC?

  • Model: model (layanan, dao, entitas)
  • Tampilan: Tampilan (jsp, html, klien aplikasi)
  • Pengontrol: Pengontrol (Servlet, Hander, Aksi)

Setelah permintaan masuk ke aplikasi JavaWeb, Pengontrol menerima permintaan tersebut, melakukan pemrosesan logika bisnis, dan terakhir mengembalikan hasilnya kepada pengguna (Tampilan + Model).

1. Perkenalan

Pada tahun-tahun awal, ketika mengoperasikan aplikasi web, pengguna langsung mengakses lapisan kontrol, dan lapisan kontrol dapat langsung mengoperasikan database:

servlet--CRUD (menambah, menghapus, memodifikasi)--&gt;database

Dalam kode servlet: memproses permintaan, respons, lompatan tampilan, pemrosesan JDBC, pemrosesan kode bisnis, dan pemrosesan kode logika

Kekurangan:Program ini sangat membengkak dan tidak kondusif untuk pemeliharaan

larutan: Tidak ada yang tidak dapat diselesaikan dengan menambahkan lapisan lain, jika ada, tambahkan lapisan lain!

2. arsitektur tiga tingkat mvc

Model

  • Pemrosesan bisnis: logika bisnis (Layanan)
  • Lapisan persistensi data: CRUD (objek persistensi data DAO)

melihat

  • menampilkan data
  • Berikan tautan untuk memulai permintaan Servlet (a, form, img...)

Pengendali (Servlet)

  • Menerima permintaan pengguna: (persyaratan, parameter permintaan, informasi sesi)
  • Serahkan ke lapisan bisnis untuk memproses kode yang sesuai
  • Kontrol tampilan melompat

Ambil login pengguna dan administrator sebagai contoh:

Lapisan pengontrol:

  1. @WebServlet("/login")
  2. public class LoginServlet extends HttpServlet {
  3. private LoginService loginService = new LoginServiceImpl();
  4. /* 处理登录的业务逻辑*/
  5. @Override
  6. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  7. String username = req.getParameter("username");
  8. String password = req.getParameter("password");
  9. String type = req.getParameter("type");
  10. Object object = loginService.login(username,password,type);
  11. if(object != null){
  12. HttpSession session = req.getSession();
  13. switch (type){
  14. case "reader":
  15. Reader reader = (Reader) object;
  16. session.setAttribute("reader",reader);
  17. //跳转到用户的首页
  18. resp.sendRedirect("/book?page=1");
  19. break;
  20. case "admin":
  21. Admin admin = (Admin) object;
  22. session.setAttribute("admin",admin);
  23. //跳转到管理员的首页
  24. resp.sendRedirect("/admin?method=findAllBorrow&page=1");
  25. break;
  26. }
  27. }else{
  28. resp.sendRedirect("login.jsp");
  29. }
  30. }
  31. }

Lapisan layanan:

  1. public interface LoginService {
  2. //利用多态,动态返回不同类型的对象
  3. public Object login(String username,String password,String type);
  4. }
  1. public class LoginServiceImpl implements LoginService {
  2. private ReaderRepository readerRepository = new ReaderRepositoryImpl();
  3. private AdminRepository adminRepository = new AdminRepositoryImpl();
  4. @Override
  5. public Object login(String username, String password,String type) {
  6. Object object = null;
  7. //业务逻辑处理:根据type的值,来选择调用不同的登录方法,去查找不同的表
  8. switch (type){
  9. case "reader":
  10. object = readerRepository.login(username,password);
  11. break;
  12. case "admin":
  13. object = adminRepository.login(username, password);
  14. break;
  15. }
  16. return object;
  17. }
  18. }

Lapisan Dao/Repositori:

  1. public interface AdminRepository {
  2. public Admin login(String username,String password);
  3. }
  1. public interface ReaderRepository {
  2. public Reader login(String username,String password);
  3. }
  1. public class AdminRepositoryImpl implements AdminRepository {
  2. //管理员的登录方法(和数据库交互)
  3. @Override
  4. public Admin login(String username, String password) {
  5. Connection connection = JDBCTools.getConnection();
  6. String sql = "select * from bookadmin where username = ? and password = ?";
  7. PreparedStatement statement = null;
  8. ResultSet resultSet = null;
  9. Admin admin = null;
  10. try {
  11. statement = connection.prepareStatement(sql);
  12. statement.setString(1,username);
  13. statement.setString(2,password);
  14. resultSet = statement.executeQuery();
  15. if(resultSet.next()){
  16. admin = new Admin(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3));
  17. }
  18. } catch (SQLException e) {
  19. e.printStackTrace();
  20. } finally {
  21. JDBCTools.release(connection,statement,resultSet);
  22. }
  23. return admin;
  24. }
  25. }
  1. public class ReaderRepositoryImpl implements ReaderRepository {
  2. //用户的登录方法(和数据库交互)
  3. @Override
  4. public Reader login(String username, String password) {
  5. Connection connection = JDBCTools.getConnection();
  6. String sql = "select * from reader where username = ? and password = ?";
  7. PreparedStatement statement = null;
  8. ResultSet resultSet = null;
  9. Reader reader = null;
  10. try {
  11. statement = connection.prepareStatement(sql);
  12. statement.setString(1,username);
  13. statement.setString(2,password);
  14. resultSet = statement.executeQuery();
  15. if(resultSet.next()){
  16. reader = new Reader(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3),resultSet.getString(4),resultSet.getString(5),resultSet.getString(6),resultSet.getString(7));
  17. }
  18. } catch (SQLException e) {
  19. e.printStackTrace();
  20. } finally {
  21. JDBCTools.release(connection,statement,resultSet);
  22. }
  23. return reader;
  24. }
  25. }