τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
JavaWeb (1: Βασικές γνώσεις και κατασκευή περιβάλλοντος)https://blog.csdn.net/xpy2428507302/article/details/140365130?spm=1001.2014.3001.5501JavaWeb (2: Servlet και Jsp, ακροατής και φίλτρο)
https://blog.csdn.net/xpy2428507302/article/details/140365159?spm=1001.2014.3001.5501
Πίνακας περιεχομένων
(1) Διεύθυνση URL βάσης δεδομένων
7. Δεξαμενή σύνδεσης βάσης δεδομένων
11. Αρχιτεκτονική τριών επιπέδων MVC
2. Αρχιτεκτονική τριών επιπέδων mvc
JDBC (Java DataBase Connectivity): Τεχνολογία σύνδεσης βάσεων δεδομένων Java
Το JDBC είναι ένα σύστημα διαχείρισης ανεξάρτητο από μια συγκεκριμένη βάση δεδομένων και μια δημόσια διεπαφή για πρόσβαση και λειτουργίες καθολικής βάσης δεδομένων SQL.
Καθορίζει ένα σύνολο προτύπων για να παρέχει έναν ενιαίο τρόπο πρόσβασης σε διαφορετικές βάσεις δεδομένων.
Το JDBC είναι ένα API εφαρμογής για πρόσβαση σε βάσεις δεδομένων, που αποτελείται από ένα σύνολο κλάσεων και διεπαφών γραμμένων σε γλώσσα Java.
Περιλαμβάνει δύο επίπεδα:
① API προσανατολισμένο σε εφαρμογές για να καλούν προγραμματιστές.
② API προσανατολισμένο στη βάση δεδομένων για τους κατασκευαστές να αναπτύξουν προγράμματα οδήγησης βάσεων δεδομένων.
Για να συνδέσετε διαφορετικές βάσεις δεδομένων με το JDBC, χρειάζεται μόνο να φορτώσετε διαφορετικά πακέτα προγραμμάτων οδήγησης βάσης δεδομένων και δεν χρειάζεται να ανησυχείτε για τις διαφορές στις γλώσσες λειτουργίας της βάσης δεδομένων.
① Δημιουργία πίνακα βάσης δεδομένων
- CREATE TABLE users(
- id INT PRIMARY KEY,
- `name` VARCHAR(40),
- `password` VARCHAR(40),
- email VARCHAR(60),
- birthday DATE
- );
- INSERT INTO users(id,`name`,`password`,email,birthday)
- INSERT INTO users(id,`name`,`password`,email,birthday)
- INSERT INTO users(id,`name`,`password`,email,birthday)
- SELECT * FROM users;
② Εισαγωγή εξαρτήσεων βάσης δεδομένων
- <!--mysql的驱动-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.31</version>
- </dependency>
③ Χρήση του JDBC:
Ⅰ Φόρτωση του προγράμματος οδήγησης της βάσης δεδομένων (η γέφυρα μεταξύ του προγράμματος java και της βάσης δεδομένων)
Ⅱ Αποκτήστε σύνδεση, μια σύνδεση μεταξύ του προγράμματος java και της βάσης δεδομένων
Ⅲ Δημιουργήστε ένα αντικείμενο Statement που στέλνει SQL στη βάση δεδομένων, που δημιουργείται από το Connection
Ⅳ Γράψτε δηλώσεις SQL (γράψτε διαφορετικά SQL ανάλογα με την επιχείρηση)
Ⅴ Εκτελέστε SQL (αν θέλετε να λάβετε την επιστρεφόμενη τιμή, δημιουργήστε ένα αντικείμενο ResultSet για να αποθηκεύσετε τα αποτελέσματα του ερωτήματος μετά την εκτέλεση της δήλωσης)
Ⅵ Κλείστε τη σύνδεση
- public class JDBCTest {
- public static void main(String[] args) throws Exception {
- //配置信息
- //要连接的数据库URL(解决中文乱码问题:useUnicode=true&characterEncoding=utf8&useSSL=true)
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- //连接的数据库时使用的用户名
- String username = "root";
- //连接的数据库时使用的密码
- String password = "123456";
- Connection conn = null;
- Statement st = null;
- ResultSet rs = null;
-
- try {
- //1.加载驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取与数据库的链接
- conn = DriverManager.getConnection(url, username, password);
- //3.获取用于向数据库发送sql语句的statement对象
- st = conn.createStatement();
- String sql = "select id,name,password,email,birthday from users";
- //4.向数据库发sql,并获取代表结果集的resultset对象
- //查:executeQuery 增删改:executeUpdate
- rs = st.executeQuery(sql);
- //5.取出结果集的数据
- while (rs.next()) {
- System.out.println("id=" + rs.getInt("id"));
- System.out.println("name=" + rs.getString("name"));
- System.out.println("password=" + rs.getString("password"));
- System.out.println("email=" + rs.getString("email"));
- System.out.println("birthday=" + rs.getDate("birthday"));
- }
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //6.关闭链接,释放资源(先开后关)
- rs.close();
- st.close();
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- }
jdbc:mysql://localhost:3306/xxx
jdbc | πρωτόκολλο |
mysql | υποπρωτόκολλο |
localhost:3306 | host:port |
xxx | βάση δεδομένων |
Πώς να γράψετε διευθύνσεις URL της βάσης δεδομένων που χρησιμοποιούνται συνήθως:
Η σύνδεση χρησιμοποιείται για την αναπαράσταση συνδέσμων βάσεων δεδομένων και η συλλογή είναι το πιο σημαντικό αντικείμενο στον προγραμματισμό της βάσης δεδομένων.
Όλες οι αλληλεπιδράσεις μεταξύ του πελάτη και της βάσης δεδομένων ολοκληρώνονται μέσω του αντικειμένου σύνδεσης., κοινές μέθοδοι αυτού του αντικειμένου:
createStatement() | Δημιουργήστε ένα αντικείμενο δήλωσης που στέλνει sql στη βάση δεδομένων |
προετοιμασία δήλωσης(sql) | Δημιουργήστε ένα αντικείμενο PrepareSatement που στέλνει προμεταγλωττισμένη sql στη βάση δεδομένων |
setAutoCommit (boolean autoCommit) | Ορίστε εάν οι συναλλαγές δεσμεύονται αυτόματα |
διαπράττω() | Υποβολή συναλλαγής στον σύνδεσμο |
επαναφορά () | Συναλλαγή επαναφοράς σε αυτόν τον σύνδεσμο |
Το αντικείμενο δήλωσης χρησιμοποιείται για την αποστολή εντολών SQL στη βάση δεδομένων Κοινές μέθοδοι αντικειμένου δήλωσης:
executeQuery (String sql) | Χρησιμοποιείται για την αποστολή δηλώσεων ερωτήματος σε δεδομένα και την επιστροφή ενός συνόλου αποτελεσμάτων ResultSet |
executeUpdate (String sql) | Χρησιμοποιείται για την αποστολή εισαγωγής, ενημέρωσης ή διαγραφής δηλώσεων στη βάση δεδομένων και επιστροφή του αριθμού των σειρών που ενημερώθηκαν στη βάση δεδομένων |
execute (String sql) | Χρησιμοποιείται για την αποστολή αυθαίρετων δηλώσεων sql στη βάση δεδομένων |
addBatch(String sql) | Βάλτε πολλές εντολές sql σε μια παρτίδα |
executeBatch() | Στείλτε μια παρτίδα δηλώσεων sql στη βάση δεδομένων για εκτέλεση |
Ειδοποίηση:
Για να βελτιωθεί η λειτουργική απόδοση, η μέθοδος εκτέλεσης γενικά δεν χρησιμοποιείται απευθείας.
Αντίθετα, χρησιμοποιήστε τα ανάλογα: executeQuery για ερωτήματα, executeUpdate για προσθήκες, διαγραφές και τροποποιήσεις.
Το ResultSet χρησιμοποιείται για την αναπαράσταση των αποτελεσμάτων εκτέλεσης εντολών Sql.
Σύνολο αποτελεσμάτων Κατά την ενθυλάκωση του συνόλου αποτελεσμάτων εκτέλεσης, χρησιμοποιήστεπαρόμοιο με το τραπέζιΟ ΤΡΟΠΟΣ。
Το αντικείμενο ResultSet διατηρεί έναν δρομέα που δείχνει στις σειρές δεδομένων πίνακα.Αρχικά, ο κέρσορας βρίσκεται πριν από την πρώτη σειρά。
Η κλήση της μεθόδου ResultSet.next() μπορεί να κάνει τον κέρσορα να δείχνει σε μια συγκεκριμένη σειρά δεδομένων και να καλέσετε τη μέθοδο getxxx για να λάβετε τα δεδομένα της σειράς.
① Λήψη οποιουδήποτε τύπου δεδομένων
getObject(int index) | Λάβετε το αντικείμενο Αντικείμενο σύμφωνα με τον καθορισμένο αριθμό στηλών |
getObject(Όνομα στήλης συμβολοσειράς) | Λάβετε το αντικείμενο Object σύμφωνα με το καθορισμένο όνομα χαρακτηριστικού |
② Λάβετε δεδομένα συγκεκριμένου τύπου, όπως λήψη τύπου String
getString(int index) | Λάβετε ένα αντικείμενο String με βάση τον καθορισμένο αριθμό στηλών |
getString (Όνομα στήλης συμβολοσειράς) | Λάβετε το αντικείμενο String σύμφωνα με το καθορισμένο όνομα χαρακτηριστικού |
③ Πώς να κάνετε κύλιση στο σύνολο αποτελεσμάτων:
Επόμενο() | μεταβείτε στην επόμενη γραμμή |
Προηγούμενος() | μετακίνηση στην προηγούμενη γραμμή |
απόλυτη (int row) | Μετακίνηση σε καθορισμένη γραμμή |
beforeFirst() | Μετακινήστε το μπροστινό μέρος του ResultSet |
afterLast() | Μεταβείτε στο τέλος του συνόλου αποτελεσμάτων |
Αφού ολοκληρωθεί η εκτέλεση του προγράμματος Jdbc, θυμηθείτε να απελευθερώσετε τα αντικείμενα που δημιουργήθηκαν από το πρόγραμμα για να αλληλεπιδράσουν με τη βάση δεδομένων κατά τη διάρκεια της διαδικασίας εκτέλεσης.
Αυτά τα αντικείμενα είναι συνήθως ResultSet, Statement και Connection αντικείμενα.
Ειδικά το αντικείμενο Connection, είναι πολύ σπάνιος πόρος και πρέπει να απελευθερωθεί αμέσως μετά τη χρήση.
Εάν η Σύνδεση δεν μπορεί να κλείσει αμέσως και σωστά, μπορεί εύκολα να οδηγήσει σε διακοπή λειτουργίας του συστήματος.
Για να διασφαλιστεί ότι ο κώδικας απελευθέρωσης πόρων μπορεί να εκτελεστεί, ο κώδικας απελευθέρωσης πόρων πρέπει επίσης να τοποθετηθεί στην πρόταση τελικού.
Υπάρχουν δύο προβλήματα κατά τη χρήση της δήλωσης για ανάπτυξη:
① Οι συμβολοσειρές πρέπει να ματίζονται συχνά και το ποσοστό σφάλματος είναι υψηλό
- String username = "zhangsan";
- String password = "123";
- String sql = "select * from users where name='"+username+"' and password='"+password+"'";
- ResultSet rs = st.executeQuery(sql);
② Υπάρχει πιθανός κίνδυνος ένεσης SQL
Έγχυση SQL: Έγχυση παράνομων δηλώσεων SQL στα δεδομένα που εισάγει ο χρήστης, με χρήση έξυπνων τεχνικών για τη συνένωση συμβολοσειρών, προκαλώντας βραχυκύκλωμα SQL, με αποτέλεσμα την κλοπή δεδομένων βάσης δεδομένων.
- public class SQLTest {
- public static void main(String[] args) throws Exception {
- // 正常登陆sql:select * from users where name='张三' and password ='123456'
- //login("张三","123456");
- // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
- login("", "123456' or '1'='1");
- }
-
- public static void login(String username, String password) throws Exception {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String dbUsername = "root";
- String dbPassword = "123456";
-
- //1.加载驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取与数据库的链接
- Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
- //3.获取用于向数据库发送sql语句的statement
- Statement st = conn.createStatement();
- String sql = "select * from users where name='" + username + "' and password='" + password + "'";
- System.out.println(sql);
- //4.向数据库发sql,并获取代表结果集的rs
- ResultSet rs = st.executeQuery(sql);
- if (rs.next()) {
- System.out.println("登录成功");
- } else {
- System.out.println("登录失败");
- }
- //6.关闭链接,释放资源
- rs.close();
- st.close();
- conn.close();
- }
- }
αποτέλεσμα λειτουργίας:
Ειδοποίηση:
Η προτεραιότητα του και στη δήλωση SQL είναι μεγαλύτερη από ή, επομένως η εκτελούμενη SQL ισοδυναμεί με την επιλογή * από τους χρήστες όπου '1' = '1'.
Λύση:Χρησιμοποιήστε το PreparedStatement, μια υποκλάση Statement, η οποία παρέχει τη λειτουργία του σύμβολο κράτησης θέσης SQL.
Δεν χρειάζεται να συνδέσετε συμβολοσειρές και τα δεδομένα που εισάγει ο χρήστης θα εντοπιστούν πλήρως, καθιστώντας το πιο ασφαλές.
- public class PSTest {
- public static void main(String[] args) throws Exception {
- // 正常登陆sql:select * from users where name='张三' and password ='123456'
- //login("张三","123456");
- // SQL 注入:select * from users where name='' and password ='123456' or '1'='1'
- login("", "123456' or '1'='1");
- }
-
- public static void login(String username, String password) throws Exception {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String dbUsername = "root";
- String dbPassword = "123456";
-
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- Connection conn = DriverManager.getConnection(url, dbUsername, dbPassword);
- //获取用于向数据库发送预编译sql语句的prepareStatement
- String sql = "select * from users where name = ? and password = ?";
- System.out.println(sql);
- PreparedStatement ps = conn.prepareStatement(sql);
- //给占位符 ? 填充数据
- ps.setString(1, username);
- ps.setString(2, password);
- ResultSet rs = ps.executeQuery();
- if (rs.next()) {
- System.out.println("登录成功");
- } else {
- System.out.println("登录失败");
- }
- rs.close();
- ps.close();
- conn.close();
- }
- }
αποτέλεσμα λειτουργίας:
Μια συναλλαγή αναφέρεται σε ένα λογικό σύνολο λειτουργιών, είτε όλες επιτυχείς είτε όλες ανεπιτυχείς (αρχή ACID).
Όταν το πρόγραμμα Jdbc αποκτήσει ένα αντικείμενο Connection από τη βάση δεδομένων, από προεπιλογή το αντικείμενο Connection θα υποβάλει αυτόματα μια συναλλαγή στη βάση δεδομένων.
Εάν θέλετε να απενεργοποιήσετε αυτήν την προεπιλεγμένη μέθοδο υποβολής και να επιτρέψετε την εκτέλεση πολλών SQL σε μία συναλλαγή, μπορείτε να χρησιμοποιήσετε την ακόλουθη δήλωση συναλλαγής ελέγχου JDBC.
Connection.setAutoCommit(false); | έναρξη συναλλαγής |
Connection.rollback(); | Συναλλαγή επαναφοράς |
Connection.commit(); | δέσμευση συναλλαγής |
① Δημιουργία πίνακα λογαριασμών
- /*创建账户表*/
- CREATE TABLE account(
- id INT PRIMARY KEY AUTO_INCREMENT,
- NAME VARCHAR(40),
- money DECIMAL(9,2)
- );
- /*插入测试数据*/
- insert into account(name,money) values('A',1000);
- insert into account(name,money) values('B',1000);
- insert into account(name,money) values('C',1000);
② Προσομοιώστε το επιχειρηματικό σενάριο όταν η μεταφορά είναι επιτυχής
- //失败后让数据库自动回滚事务
- public class Demo {
- public static void main(String[] args) {
- String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String username = "root";
- String password = "123456";
- Connection conn = null;
- try {
- Class.forName("com.mysql.cj.jdbc.Driver");
- conn = DriverManager.getConnection(url, username, password);
-
- //通知数据库开启事务,false表示开启
- conn.setAutoCommit(false);
-
- String sql1 = "update account set money=money-100 where name = 'A' ";
- conn.prepareStatement(sql1).executeUpdate();
-
- //模拟执行完SQL1之后程序出现了异常而导致后面的SQL无法正常执行,事务也无法正常提交
- int x = 1/0;
-
- String sql2 = "update account set money=money+100 where name = 'B' ";
- conn.prepareStatement(sql2)executeUpdate();
-
- //sql1 和 sql2都顺利执行,就提交事务
- conn.commit();
- System.out.println("成功!!!");
- } catch (Exception e) {
- //出现异常,通知数据库回滚事务
- conn.rollback();
- e.printStackTrace();
- } finally {
- conn.close();
- }
- }
- }
Σε διαφορετικά αιτήματα, πρέπει να συνδέεστε στη βάση δεδομένων και να αποδεσμεύετε πόρους κάθε φορά και θα γράφονται πολλοί επαναλαμβανόμενοι κώδικας.
Ενσωματώστε τις λειτουργίες προετοιμασίας και απελευθέρωσης της σύνδεσης της βάσης δεδομένων σε μια κλάση εργαλείων και καλέστε την απευθείας όταν τη χρησιμοποιείτε για να αποφύγετε τη σύνταξη επαναλαμβανόμενου κώδικα.
- public class JdbcUtil {
- private static Connection connection;
- private static String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=true";
- private static String username = "root";
- private static String password = "123456";
-
- //驱动(类)只需要加载一次,放静态代码块即可
- static {
- try {
- //加载数据库驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- // 获取数据库连接对象
- public static Connection getConnection() throws SQLException {
- return DriverManager.getConnection(url, username, password);
- }
-
- // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
- public static void release(Connection conn, Statement st, ResultSet rs) {
- try {
- if (rs != null) {
- rs.close();
- }
- if (st != null) {
- st.close();
- }
- if (conn != null) {
- conn.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Περίπτωση κλήσης, όπως: προσθήκη χρήστη
-
- public void add(String name, String password) {
- Connection conn = null;
- PreparedStatement ps = null;
- try {
- conn = JdbcUtil.getConnection();
- String sql = "insert into users(name,password) values(?,?)";
- ps = conn.prepareStatement(sql);
- ps.setString(1, name);
- ps.setString(2, password);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JdbcUtil.release(conn, ps, null);
- }
- }
Διαδικασία ανάπτυξης JDBC:
Ⅰ Φόρτωση του προγράμματος οδήγησης της βάσης δεδομένων (χρειάζεται να φορτωθεί μόνο μία φορά)
Ⅱ Δημιουργία σύνδεσης βάσης δεδομένων (Σύνδεση)
Ⅲ Δημιουργήστε ένα αντικείμενο Statement που στέλνει SQL στη βάση δεδομένων, που δημιουργείται από το Connection
Ⅳ Σύνταξη δηλώσεων SQL
Ⅴ Εκτέλεση SQL (Query-->ResultSet αντικείμενο λαμβάνει σύνολο αποτελεσμάτων)
Ⅵ Κλείστε τη σύνδεση και αποδεσμεύστε πόρους
Το αντικείμενο σύνδεσης βάσης δεδομένων λαμβάνεται μέσω του DriverManager Κάθε φορά που λαμβάνεται, πρέπει να κάνετε αίτηση στη βάση δεδομένων για να αποκτήσετε σύνδεση και να επαληθεύσετε το όνομα χρήστη και τον κωδικό πρόσβασης.
Οι χρήστες πρέπει να λάβουν έναν σύνδεσμο από τη βάση δεδομένων για κάθε αίτημα και η δημιουργία μιας σύνδεσης με τη βάση δεδομένων συνήθως καταναλώνει σχετικά μεγάλους πόρους και χρειάζεται πολύ χρόνο για να δημιουργηθεί.
Κάθε φορά που εκτελείται η πρόταση SQL, η σύνδεση αποσυνδέεται, γεγονός που θα προκαλέσει σπατάλη πόρων και οι πόροι σύνδεσης της βάσης δεδομένων δεν επαναχρησιμοποιούνται σωστά.
Υποθέτοντας ότι ο ιστότοπος δέχεται 100.000 επισκέψεις την ημέρα, ο διακομιστής βάσης δεδομένων πρέπει να δημιουργήσει 100.000 συνδέσεις, κάτι που είναι τεράστια σπατάλη πόρων της βάσης δεδομένων και μπορεί εύκολα να προκαλέσει υπερχείλιση μνήμης διακομιστή βάσης δεδομένων και επέκταση του μηχανήματος.
Λύση: Δεξαμενή σύνδεσης βάσης δεδομένων
Η βασική ιδέα της δεξαμενής σύνδεσης βάσης δεδομένων:
Δημιουργήστε ένα buffer pool για τη βάση δεδομένων και τοποθετήστε έναν ορισμένο αριθμό αντικειμένων σύνδεσης στο buffer pool εκ των προτέρων.
Όταν θέλετε να αποκτήσετε μια σύνδεση βάσης δεδομένων, χρειάζεται μόνο να πάρετε ένα αντικείμενο από το buffer pool.
Μετά τη χρήση, τοποθετήστε το ξανά στο buffer pool για το επόμενο αίτημα, επιτυγχάνοντας επαναχρησιμοποίηση πόρων χωρίς την ανάγκη επαναλαμβανόμενης δημιουργίας.
Όταν δεν υπάρχουν αντικείμενα σύνδεσης σε αδράνεια στο χώρο συγκέντρωσης σύνδεσης της βάσης δεδομένων, νέα αιτήματα θα εισέλθουν στην ουρά αναμονής και θα περιμένουν άλλα νήματα να αποδεσμεύσουν τη σύνδεση.
Η ομάδα σύνδεσης της βάσης δεδομένων του JDBC ολοκληρώνεται με τη χρήση της διεπαφής javax.sql.DataSource είναι η διεπαφή που παρέχεται επίσημα από τη java.
Όταν το χρησιμοποιούν, οι προγραμματιστές δεν χρειάζεται να υλοποιούν οι ίδιοι τη διεπαφή και μπορούν να χρησιμοποιήσουν εργαλεία τρίτων.
Το C3P0 είναι μια ευρέως χρησιμοποιούμενη υλοποίηση τρίτου μέρους Στην πραγματική ανάπτυξη, το C3P0 μπορεί να χρησιμοποιηθεί απευθείας για την ολοκλήρωση της λειτουργίας της ομάδας σύνδεσης βάσης δεδομένων.
Βήματα για χρήση:
① Εισαγάγετε εξαρτήσεις στο pom.xml
- <dependency>
- <groupId>com.mchange</groupId>
- <artifactId>c3p0</artifactId>
- <version>0.9.5.2</version>
- </dependency>
② Γράψτε κώδικα
- public class DataSourceTest {
- public static void main(String[] args) {
- try {
- //创建C3P0数据库连接池
- ComboPooledDataSource dataSource=new ComboPooledDataSource();
- dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
- dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8");
- dataSource.setUser("root");
- dataSource.setPassword("123456");
- //设置初始化连接个数
- dataSource.setInitialPoolSize(5);
- //设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限)
- dataSource.setMaxPoolSize(20);
- //当连接对象不够时,再次申请的连接对象个数
- dataSource.setAcquireIncrement(5);
- //设置最小连接数(当连接池中剩余2个连接对象时,就去申请 --> 提前做准备)
- dataSource.setMinPoolSize(2);
- Connection conn=dataSource.getConnection();
-
- //SQL操作...
-
- //将连接还回到数据库连接池中
- conn.close();
- } catch (PropertyVetoException e) {
- e.printStackTrace();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Ειδοποίηση:
Σύνδεση που λαμβάνεται μέσω παραδοσιακής μεθόδου: com.mysql.cj.jdbc.ConnectionImpl@3c153a1
Η σύνδεση αποκτήθηκε από το C3P0: com.mchange.v2.c3p0.impl.NewProxyConnection@6156496
Έτσι,Αν και όλοι καλούν τη μέθοδο κλεισίματος, οι κλάσεις υλοποίησης είναι διαφορετικές, επομένως η επανεγγραφή της μεθόδου είναι επίσης διαφορετική.。
Η μέθοδος κλεισίματος στο C3P0 δεν καταστρέφει άμεσα τον πόρο σύνδεσης, αλλά επιστρέφει τη σύνδεση στο χώρο συγκέντρωσης σύνδεσης της βάσης δεδομένων.
Η παραπάνω μέθοδος ρύθμισης παραμέτρων για το χώρο συγκέντρωσης σύνδεσης της βάσης δεδομένων γράφεται απευθείας στο πρόγραμμα Java.
Αυτό εγκρίνεταισκληρό κώδικαΟ ΤΡΟΠΟΣ,Κάθε φορά που αλλάζετε τη διαμόρφωσηΧρειάζεται εκ νέου μεταγλώττιση, δημιουργήστε νέα αρχεία κλάσης, η απόδοση είναι πολύ χαμηλή。
Στην πραγματική ανάπτυξη, οι πληροφορίες διαμόρφωσης του C3P0 ορίζονται σε ένα αρχείο xml και το πρόγραμμα java χρειάζεται μόνο να φορτώσει το αρχείο διαμόρφωσης για να ολοκληρώσει τη λειτουργία προετοιμασίας του χώρου συγκέντρωσης σύνδεσης βάσης δεδομένων.
Στη συνέχεια, χρειάζεται μόνο να τροποποιήσετε τη διαμόρφωση και να τροποποιήσετε τη διαμόρφωση σε xml χωρίς να κάνετε εκ νέου μεταγλώττιση.
Βήματα για χρήση:
① Στον κατάλογο πόρων, δημιουργήστε ένα νέο αρχείο με το όνομα c3p0-config.xml
② Συμπληρώστε τις πληροφορίες διαμόρφωσης στο c3p0-config.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <c3p0-config>
- <!--配置连接池mysql-->
- <named-config name="C3P0Test">
- <!-- 指定连接数据源的基本属性 -->
- <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
- <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8</property>
- <property name="user">root</property>
- <property name="password">123456</property>
-
- <!-- 设置初始化连接个数 -->
- <property name="initialPoolSize">5</property>
- <!-- 设置最大连接个数(连接池中不够,可以继续申请,申请后最终的上限) -->
- <property name="maxPoolSize">20</property>
- <!-- 当连接对象不够时,再次申请的连接对象个数 -->
- <property name="acquireIncrement">5</property>
- <!-- 设置最小连接数(当连接池中剩余2个连接对象时,就去申请 -> 提前做准备) -->
- <property name="minPoolSize">2</property>
- </named-config>
- </c3p0-config>
③Γράψτε πρόγραμμα Java
- public class DataSourceTest {
- public static void main(String[] args) {
- try {
- //创建C3P0数据库连接池
- ComboPooledDataSource dataSource=new ComboPooledDataSource("C3P0Test");
- Connection conn=dataSource.getConnection();
- System.out.println(conn);
- //将连接还回到数据库连接池中
- conn.close();
- }catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
Ειδοποίηση:
① Η παράμετρος στη μέθοδο κατασκευής ComboPooledDataSource είναι η τιμή του χαρακτηριστικού name της ετικέτας named-config που έχει ρυθμιστεί στο c3p0-config.xml.
② Αυτή τη στιγμή, η κλάση εργαλείων JDBC μπορεί να τροποποιηθεί ως εξής:
- public class JdbcUtil {
- private static DataSource dataSource;
-
- static {
- dataSource = new ComboPooledDataSource("C3P0Test");
- }
-
- // 获取数据库连接对象
- public static Connection getConnection() throws SQLException {
- Connection conn = null;
- try {
- conn = dataSource.getConnection();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return conn;
- }
-
- // 释放资源(利用多态:Statement 和 PreparedStatement 都可以传进来)
- public static void release(Connection conn, Statement st, ResultSet rs) {
- try {
- if (rs != null) {
- rs.close();
- }
- if (st != null) {
- st.close();
- }
- if (conn != null) {
- conn.close();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
- public static Student findById(Integer idx) {
- Connection conn = null;
- PreparedStatement st = null;
- ResultSet rs = null;
- Student stu = null;
- try {
- conn = JdbcUtil.getConnection();
-
- String sql = "select * from student where id = ?";
- PreparedStatement ps = conn.prepareStatement(sql);
- //给占位符 ? 填充数据
- ps.setInt(1, idx);
- rs = ps.executeQuery();
- //取出结果集的数据
- while (rs.next()) {
- Integer id = rs.getInt(1);
- String name = rs.getString(2);
- Double score = rs.getDouble(3);
- Date birthday = rs.getDate(4);
- stu = new Student(id, name, score, birthday);
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //关闭链接,释放资源
- rs.close();
- st.close();
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- return stu;
- }
Στον παραπάνω κώδικα, οι λειτουργίες πλήρωσης των placeholders με δεδομένα και εξαγωγής των δεδομένων από το σύνολο αποτελεσμάτων είναι πολύ επαχθείς.
Εάν υπάρχουν 100 χαρακτηριστικά στον πίνακα Student, τότε θα πρέπει να γράψουμε 100 σειρές στον βρόχο while για να ανακτήσουμε τα δεδομένα και μπορεί επίσης να χρειαστούν πολλές σειρές για να συμπληρωθούν τα σύμβολα κράτησης θέσης.
Λύση:Τα DBUtils μπορούν να βοηθήσουν τους προγραμματιστές να ολοκληρώσουν την ενθυλάκωση δεδομένων (αντιστοίχιση συνόλων αποτελεσμάτων σε αντικείμενα Java).
Βήματα για χρήση:
① Εισαγάγετε εξαρτήσεις στο pom.xml
- <dependency>
- <groupId>commons-dbutils</groupId>
- <artifactId>commons-dbutils</artifactId>
- <version>1.6</version>
- </dependency>
② Γράψτε κώδικα
- public static Student findById(Integer idx) {
- Connection conn = null;
- Student stu = null;
- try {
- conn = JdbcUtil.getConnection();
-
- String sql = "select * from student where id = ?";
- //使用DBUtils
- QueryRunner qr = new QueryRunner();
- stu = qr.query(conn, sql, new BeanHandler<>(Student.class), idx);
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- try {
- //关闭链接,释放资源
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- return stu;
- }
Σε αυτό το σημείο, η συμπλήρωση των θέσεων και η αφαίρεση του συνόλου αποτελεσμάτων μπορεί να ολοκληρωθεί με δύο γραμμές κώδικα.
λεπτομέρεια:
① Η μέθοδος ερωτήματος πρέπει να περάσει σε 4 παραμέτρους:
Αντικείμενο σύνδεσης
Δήλωση SQL
Το αντικείμενο κλάσης υλοποίησης της διεπαφής ResultSetHandler (ο τύπος του αντικειμένου που έχει μετατραπεί πρέπει να είναι: Student.class)
Παράμετροι για τη συμπλήρωση συμβόλων κράτησης θέσης
② Η διεπαφή ResultSetHandler χρησιμοποιείται για την επεξεργασία συνόλων αποτελεσμάτων. Μπορεί να μετατρέψει τα ερωτήματα σε αντικείμενα Java.
BeanHandler | Αντιστοιχίστε το σύνολο αποτελεσμάτων σε ένα αντικείμενο Java (όπως αντικείμενο Student) |
BeanListHandler | Αντιστοιχίστε το σύνολο αποτελεσμάτων σε μια συλλογή λίστας (όπως: Λίστα<Student > ) |
Χάρτης Χειριστής | Αντιστοιχίστε το σύνολο αποτελεσμάτων σε ένα αντικείμενο συλλογής χάρτη (δηλαδή: Χάρτης<String,Object> κλειδί: όνομα χαρακτηριστικού: τιμή χαρακτηριστικού) |
MapListHandler | Αντιστοιχίστε το σύνολο των αποτελεσμάτων σε μια συλλογή MapList (δηλ.: Λίστα <Map<<String,Object> >) |
③ Η παράμετρος που πρέπει να συμπληρώσετε το σύμβολο κράτησης θέσης είναι μια μεταβλητή παράμετρος, επομένως οποιοσδήποτε αριθμός παραμέτρων μπορεί να μεταβιβαστεί για να καλύψει τις διαφορετικές ανάγκες των χρηστών.
④ Η κλάση αντικειμένου που έχει μετατραπεί (κλάση σπουδαστή) πρέπει να έχει κατασκευαστή χωρίς παραμέτρους, διαφορετικά το πρόγραμμα θα αναφέρει ένα σφάλμα.
λόγος:Το κάτω επίπεδο βρίσκει αυτήν την κλάση μέσω Student.class και, στη συνέχεια, μέσωμηχανισμός ανάκλασηςΒρείτε τον κατασκευαστή χωρίς παραμέτρους αυτής της κλάσης και δημιουργήστε το αντικείμενό του.
⑤ Το όνομα του χαρακτηριστικού στην κλάση πρέπει να είναι ακριβώς το ίδιο με το όνομα του πεδίου στον πίνακα της βάσης δεδομένων.
Επειδή μετά τη δημιουργία του αντικειμένου, κατά την εκχώρηση τιμών στις ιδιότητες του αντικειμένου με βάση το σύνολο αποτελεσμάτων, η αναζήτηση και η εκχώρηση εκτελούνται με βάση το όνομα.
Τι είναι το MVC;
Μετά την είσοδο του αιτήματος στην εφαρμογή JavaWeb, ο Ελεγκτής λαμβάνει το αίτημα, εκτελεί επεξεργασία επιχειρηματικής λογικής και τελικά επιστρέφει το αποτέλεσμα στον χρήστη (Προβολή + Μοντέλο).
Τα πρώτα χρόνια, όταν λειτουργούσαν εφαρμογές Ιστού, οι χρήστες είχαν άμεση πρόσβαση στο επίπεδο ελέγχου και το επίπεδο ελέγχου μπορούσε να λειτουργήσει απευθείας τη βάση δεδομένων:
servlet--CRUD (προσθήκη, διαγραφή, τροποποίηση)-->βάση δεδομένων
Στον κώδικα servlet: επεξεργασία αιτημάτων, απαντήσεις, άλματα προβολής, επεξεργασία JDBC, επεξεργασία επιχειρηματικού κώδικα και επεξεργασία λογικού κώδικα
Μειονεκτήματα:Το πρόγραμμα είναι πολύ φουσκωμένο και δεν ευνοεί τη συντήρηση
λύση: Δεν υπάρχει τίποτα που δεν μπορεί να λύσει η προσθήκη ενός άλλου στρώματος, αν υπάρχει, προσθέστε ένα άλλο επίπεδο!
Μοντέλο
θέα
Ελεγκτής (Servlet)
Πάρτε για παράδειγμα τη σύνδεση χρήστη και διαχειριστή:
Επίπεδο ελεγκτή:
- @WebServlet("/login")
- public class LoginServlet extends HttpServlet {
-
- private LoginService loginService = new LoginServiceImpl();
-
- /* 处理登录的业务逻辑*/
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String username = req.getParameter("username");
- String password = req.getParameter("password");
- String type = req.getParameter("type");
- Object object = loginService.login(username,password,type);
- if(object != null){
- HttpSession session = req.getSession();
- switch (type){
- case "reader":
- Reader reader = (Reader) object;
- session.setAttribute("reader",reader);
- //跳转到用户的首页
- resp.sendRedirect("/book?page=1");
- break;
- case "admin":
- Admin admin = (Admin) object;
- session.setAttribute("admin",admin);
- //跳转到管理员的首页
- resp.sendRedirect("/admin?method=findAllBorrow&page=1");
- break;
- }
- }else{
- resp.sendRedirect("login.jsp");
- }
- }
-
- }
Επίπεδο υπηρεσίας:
- public interface LoginService {
- //利用多态,动态返回不同类型的对象
- public Object login(String username,String password,String type);
- }
- public class LoginServiceImpl implements LoginService {
-
- private ReaderRepository readerRepository = new ReaderRepositoryImpl();
- private AdminRepository adminRepository = new AdminRepositoryImpl();
-
- @Override
- public Object login(String username, String password,String type) {
- Object object = null;
- //业务逻辑处理:根据type的值,来选择调用不同的登录方法,去查找不同的表
- switch (type){
- case "reader":
- object = readerRepository.login(username,password);
- break;
- case "admin":
- object = adminRepository.login(username, password);
- break;
- }
- return object;
- }
- }
Επίπεδο Dao/Repository:
- public interface AdminRepository {
- public Admin login(String username,String password);
- }
- public interface ReaderRepository {
- public Reader login(String username,String password);
- }
- public class AdminRepositoryImpl implements AdminRepository {
- //管理员的登录方法(和数据库交互)
- @Override
- public Admin login(String username, String password) {
- Connection connection = JDBCTools.getConnection();
- String sql = "select * from bookadmin where username = ? and password = ?";
- PreparedStatement statement = null;
- ResultSet resultSet = null;
- Admin admin = null;
- try {
- statement = connection.prepareStatement(sql);
- statement.setString(1,username);
- statement.setString(2,password);
- resultSet = statement.executeQuery();
- if(resultSet.next()){
- admin = new Admin(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3));
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JDBCTools.release(connection,statement,resultSet);
- }
- return admin;
- }
- }
- public class ReaderRepositoryImpl implements ReaderRepository {
- //用户的登录方法(和数据库交互)
- @Override
- public Reader login(String username, String password) {
- Connection connection = JDBCTools.getConnection();
- String sql = "select * from reader where username = ? and password = ?";
- PreparedStatement statement = null;
- ResultSet resultSet = null;
- Reader reader = null;
- try {
- statement = connection.prepareStatement(sql);
- statement.setString(1,username);
- statement.setString(2,password);
- resultSet = statement.executeQuery();
- if(resultSet.next()){
- reader = new Reader(resultSet.getInt(1),resultSet.getString(2),resultSet.getString(3),resultSet.getString(4),resultSet.getString(5),resultSet.getString(6),resultSet.getString(7));
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JDBCTools.release(connection,statement,resultSet);
- }
- return reader;
- }
- }