Teknologian jakaminen

JavaWeb (3: JDBC ja MVC)

2024-07-12

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

JavaWeb (1: Perustiedot ja ympäristön rakentaminen)icon-default.png?t=N7T8https://blog.csdn.net/xpy2428507302/article/details/140365130?spm=1001.2014.3001.5501JavaWeb (2: Servlet ja Jsp, kuuntelija ja suodatin)icon-default.png?t=N7T8https://blog.csdn.net/xpy2428507302/article/details/140365159?spm=1001.2014.3001.5501

Sisällysluettelo

10. JDBC

1 Yleiskatsaus

2. Kirjoita JDBC-ohjelma

3. Yksityiskohtainen analyysi

(1) Tietokannan URL-osoite

(2) Liitäntäluokka

(3) Lausuntoluokka

(4) ResultSet-luokka

(5) Vapauta resurssit

4.SQL-injektioongelma

5.JDBC-tapahtumat

6.JDBC-työkaluluokka

7. Tietokantayhteyspooli

(1 Yleiskatsaus

(2) Käyttö

8.DBUtils

11. Kolmikerroksinen MVC-arkkitehtuuri

1. Esittely

2. mvc kolmikerroksinen arkkitehtuuri


10. JDBC

1 Yleiskatsaus

JDBC (Java DataBase Connectivity): Java-tietokantayhteystekniikka

JDBC on tietystä tietokannasta riippumaton hallintajärjestelmä ja julkinen käyttöliittymä yleiseen SQL-tietokannan käyttöön ja toimintoihin.

Määrittää joukon standardeja, jotka tarjoavat yhtenäisen tavan käyttää erilaisia ​​tietokantoja.

JDBC on sovellusrajapinta tietokantakäyttöön, joka koostuu joukosta Java-kielellä kirjoitettuja luokkia ja rajapintoja.

Sisältää kaksi tasoa:

① Sovellussuuntautunut sovellusliittymä ohjelmoijien kutsuttavaksi.

② Tietokantasuuntautunut API valmistajille tietokanta-ohjaimien kehittämiseen.

Yhdistääksesi erilaisia ​​tietokantoja JDBC:hen sinun tarvitsee vain ladata erilaisia ​​tietokantaohjainpaketteja, eikä sinun tarvitse huolehtia tietokantojen käyttökielten eroista.

2. Kirjoita JDBC-ohjelma

① Luo tietokantataulukko

  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;

② Tuo tietokantariippuvuudet

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

③ JDBC:n käyttö:

Ⅰ Lataa tietokantaohjain (java-ohjelman ja tietokannan välinen silta).

Ⅱ Hanki yhteys, Java-ohjelman ja tietokannan välinen yhteys

Ⅲ Luo lausekeobjekti, joka lähettää yhteyden luoman SQL:n tietokantaan

Ⅳ Kirjoita SQL-lauseita (kirjoita erilaisia ​​SQL-lauseita liiketoiminnan mukaan)

Ⅴ Suorita SQL (jos haluat saada palautusarvon, luo ResultSet-objekti tallentaaksesi kyselyn tulokset lauseen suorittamisen jälkeen)

Ⅵ Sulje yhteys

  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. Yksityiskohtainen analyysi

(1) Tietokannan URL-osoite

jdbc:mysql://localhost:3306/xxx

jdbcprotokollaa
mysqlaliprotokolla
localhost: 3306isäntä: portti
xxxtietokanta

Kuinka kirjoittaa yleisesti käytettyjä tietokannan URL-osoitteita:

  • Oracle kirjoitus: jdbc:oracle:thin:@paikallinen isäntä:1521:xxx
  • SqlServer写法:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=xxx
  • MySql-kirjoitusmenetelmä: jdbc:mysql://localhost:3306/xxx

(2) Liitäntäluokka

Yhteyttä käytetään edustamaan tietokantalinkkejä, ja kokoelma on tietokantaohjelmoinnin tärkein kohde.

Kaikki asiakkaan ja tietokannan väliset vuorovaikutukset suoritetaan yhteysobjektin kautta., tämän objektin yleiset menetelmät:

CreateStatement()Luo lausekeobjekti, joka lähettää sql:n tietokantaan
valmistaa lausunto (sql)Luo PrepareSatement-objekti, joka lähettää esikäännetyn sql:n tietokantaan
setAutoCommit(boolen automaattinen toimitus)Määritä, sitovatko tapahtumat automaattisesti
tehdä()Ilmoita tapahtuma linkistä
palautus()Palautustapahtuma tästä linkistä

(3) Lausuntoluokka

Lausekeobjektia käytetään SQL-käskyjen lähettämiseen tietokantaan.

executeQuery(merkkijono sql)Käytetään kyselylausekkeiden lähettämiseen tietoihin ja ResultSet-tulosjoukon palauttamiseen
executeUpdate(String sql)Käytetään lisäys-, päivitys- tai poistolausekkeiden lähettämiseen tietokantaan ja tietokannassa päivitettyjen rivien määrän palauttamiseen
suorita (merkkijono sql)Käytetään mielivaltaisten sql-käskyjen lähettämiseen tietokantaan
addBatch(String sql)Laita useita sql-lauseita eräksi
executeBatch()Lähetä joukko sql-lauseita tietokantaan suoritettavaksi

Ilmoitus:

Toiminnan tehokkuuden parantamiseksi suoritustapaa ei yleensä käytetä suoraan.

Käytä sen sijaan niitä vastaavasti: executeQuery kyselyihin; executeUpdate lisäyksiin, poistoihin ja muokkauksiin.

(4) ResultSet-luokka

ResultSetiä käytetään edustamaan Sql-käskyjen suoritustuloksia.

Tulossarja Kun kapseloit suoritustulosjoukkoa, käytäsamanlainen kuin pöytätapa

ResultSet-objekti ylläpitää kohdistinta, joka osoittaa taulukon tietoriveille.Aluksi kohdistin on ennen ensimmäistä riviä

ResultSet.next()-menetelmän kutsuminen voi saada kohdistimen osoittamaan tiettyä tietoriviä ja kutsua getxxx-metodia rivin tietojen saamiseksi.

① Hanki kaikentyyppisiä tietoja

getObject(int index)

Hanki Object-objekti määritetyn sarakkeiden lukumäärän mukaan

getObject(merkkijono sarakkeen nimi)Hanki Object-objekti määritetyn attribuutin nimen mukaan

② Hae määritetyn tyyppisiä tietoja, kuten merkkijonotyyppiä

getString(int-indeksi)

Hanki merkkijono-objekti määritetyn sarakkeiden määrän perusteella

getString(merkkijonosarakkeen nimi)Hanki String-objekti määritetyn attribuutin nimen mukaan

③ Tulosjoukon vierittäminen: 

Seuraava()siirtyä seuraavalle riville
Edellinen()siirtyä edelliselle riville
absoluuttinen (sisäinen rivi)Siirry määritetylle riville
ennen ensimmäistä()Siirrä tulosjoukon etuosaa
viimeisen jälkeen()Siirry tulosjoukon loppuun

(5) Vapauta resurssit

Kun Jdbc-ohjelma on suoritettu, muista vapauttaa ohjelman luomat objektit ollakseen vuorovaikutuksessa tietokannan kanssa ajon aikana.

Nämä objektit ovat yleensä ResultSet-, Statement- ja Connection-objekteja.

Erityisesti Connection-objekti on erittäin harvinainen resurssi ja se on vapautettava heti käytön jälkeen.

Jos yhteyttä ei voida sulkea nopeasti ja oikein, se voi helposti johtaa järjestelmän seisokkiin.

Resurssin julkaisukoodin suorittamisen varmistamiseksi myös resurssin julkaisukoodi on sijoitettava final-lauseeseen.

4.SQL-injektioongelma

Statementin käytössä kehitystyössä on kaksi ongelmaa:

① Merkkijonoja on jaettava usein, ja virheprosentti on korkea

  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);

② On olemassa SQL-lisäyksen riski

SQL-injektio: laittomien SQL-käskyjen lisääminen käyttäjän syöttämiin tietoihin käyttämällä älykkäitä tekniikoita merkkijonojen liittämiseen, mikä aiheuttaa SQL-oikosulun ja varastaa näin tietokantatietoja.

  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. }

operaation tulos:

Ilmoitus:

SQL-käskyn ja -käskyn prioriteetti on suurempi kuin tai, joten suoritettu SQL vastaa *:n valitsemista käyttäjistä, joissa '1' = '1';


Ratkaisu:Käytä PreparedStatementia, Statementin alaluokkaa, joka tarjoaa SQL-paikkamerkin toiminnon.

Merkkijonoja ei tarvitse yhdistää, ja käyttäjän syöttämät tiedot tunnistetaan täysin, mikä tekee niistä turvallisempaa.

  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. }

operaation tulos:

5.JDBC-tapahtumat

Tapahtumalla tarkoitetaan loogista joukkoa toimintoja, joko kaikki onnistuneita tai kaikki epäonnistuneita (ACID-periaate).

Kun Jdbc-ohjelma hankkii yhteysobjektin tietokannasta, oletusarvoisesti Connection-objekti lähettää tapahtuman tietokantaan automaattisesti.

Jos haluat poistaa tämän oletuslähetystavan käytöstä ja sallia useiden SQL:ien suorittamisen yhdessä tapahtumassa, voit käyttää seuraavaa JDBC-ohjaustapahtumakäskyä.

Connection.setAutoCommit(false);

aloittaa kauppa
Connection.rollback();Palautustapahtuma
Connection.commit();tehdä kauppa

① Luo tilitaulukko

  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);

② Simuloi liiketoimintaskenaariota, kun siirto onnistuu

  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.JDBC-työkaluluokka

Eri pyynnöissä sinun on muodostettava yhteys tietokantaan ja vapautettava resurssit joka kerta, ja paljon toistuvaa koodia kirjoitetaan.

Kapseloi tietokantayhteyden valmistelu- ja julkaisutoiminnot työkaluluokkaan ja kutsu se suoraan sitä käytettäessä välttääksesi toistuvan koodin kirjoittamisen.

  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. }

Puhelutapaus, kuten: lisää käyttäjä

  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. Tietokantayhteyspooli

(1 Yleiskatsaus

JDBC-kehitysprosessi:

Ⅰ Lataa tietokantaohjain (täytyy ladata vain kerran)

Ⅱ Muodosta tietokantayhteys (yhteys)

Ⅲ Luo lausekeobjekti, joka lähettää yhteyden luoman SQL:n tietokantaan

Ⅳ SQL-lauseiden kirjoittaminen

Ⅴ Suorita SQL (Query--&gt; ResultSet -objekti vastaanottaa tulosjoukon)

Ⅵ Sulje yhteys ja vapauta resurssit


Tietokantayhteysobjekti hankitaan DriverManagerin kautta Joka kerta, kun se hankitaan, sinun on haettava tietokantaa yhteyden saamiseksi ja tarkistettava käyttäjänimi ja salasana.

Käyttäjien on hankittava linkki tietokannasta jokaista pyyntöä varten, ja yhteyden luominen tietokantaan kuluttaa yleensä suhteellisen suuria resursseja ja kestää kauan.

Joka kerta kun SQL-käsky suoritetaan, yhteys katkeaa, mikä aiheuttaa resurssien tuhlausta ja tietokantayhteysresursseja ei käytetä uudelleen kunnolla.

Olettaen, että verkkosivustolla käy 100 000 käyntiä päivässä, tietokantapalvelimen on luotava 100 000 yhteyttä, mikä on valtavaa tietokantaresurssien tuhlausta ja voi helposti aiheuttaa tietokantapalvelimen muistin ylivuotoa ja koneen laajenemista.

Ratkaisu: Tietokantayhteyspooli

Tietokantayhteyspoolin perusidea:

Perusta tietokannan puskurivarasto ja laita tietty määrä yhteysobjekteja puskurivarantoon etukäteen.

Kun haluat muodostaa tietokantayhteyden, sinun tarvitsee vain ottaa objekti puskurivarannosta.

Aseta se käytön jälkeen takaisin puskurivarastoon seuraavaa pyyntöä varten, jolloin resurssit voidaan käyttää uudelleen ilman toistuvaa luomista.

Jos tietokannan yhteyspoolissa ei ole käyttämättömiä yhteysobjekteja, uudet pyynnöt tulevat odotusjonoon ja odottavat, että muut säikeet vapauttavat yhteyden.

(2) Käyttö

JDBC:n tietokantayhteys on valmis käyttämällä javax.sql.DataSource-liitäntää. DataSource on javan virallisesti tarjoama käyttöliittymä.

Sitä käytettäessä kehittäjien ei tarvitse toteuttaa käyttöliittymää itse, vaan he voivat käyttää kolmannen osapuolen työkaluja.

C3P0 on yleisesti käytetty kolmannen osapuolen toteutus Varsinaisessa kehityksessä C3P0:ta voidaan käyttää suoraan tietokantayhteyspoolin toiminnan suorittamiseen.

Käyttövaiheet:

① Tuo riippuvuudet pom.xml:ssä

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

② Kirjoita koodi

  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. }

Ilmoitus:

Yhteys saatu perinteisellä menetelmällä: com.mysql.cj.jdbc.ConnectionImpl@3c153a1

Yhteys hankittiin C3P0:lla: com.mchange.v2.c3p0.impl.NewProxyConnection@6156496

niin,Vaikka ne kaikki kutsuvat sulkemismenetelmää, toteutusluokat ovat erilaisia, joten myös menetelmän uudelleenkirjoitus on erilainen.

C3P0:n sulkemismenetelmä ei tuhoa suoraan yhteysresurssia, vaan palauttaa yhteyden tietokannan yhteyspooliin.


Yllä oleva menetelmä parametrien asettamiseen tietokantayhteyspoolille on kirjoitettu suoraan Java-ohjelmaan.

Tämä on hyväksyttykovakooditapa,Aina kun muutat asetuksiaPitää kääntää uudelleen, luoda uusia luokkatiedostoja, tehokkuus on liian alhainen

Varsinaisessa kehityksessä C3P0:n konfigurointitiedot määritellään xml-tiedostossa, ja java-ohjelman tarvitsee vain ladata määritystiedosto suorittaakseen tietokantayhteyspoolin alustustoiminnon loppuun.

Myöhemmin sinun tarvitsee vain muokata kokoonpanoa ja muokata kokoonpanoa xml-muodossa ilman uudelleenkääntämistä.

Käyttövaiheet:

① Luo resurssihakemistoon uusi tiedosto nimeltä c3p0-config.xml

② Täytä määritystiedot tiedostoon 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>

③ Kirjoita Java-ohjelma

  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. }

Ilmoitus:

① ComboPooledDataSource-rakennusmenetelmän parametri on tiedostossa c3p0-config.xml määritetyn named-config-tunnisteen name-attribuutin arvo.

② Tällä hetkellä JDBC-työkaluluokkaa voidaan muokata seuraavasti:

  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.DBUtils

  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. }

Yllä olevassa koodissa toiminnot paikkamerkkien täyttäminen tiedoilla ja tietojen poimiminen tulosjoukosta ovat liian hankalia.

Jos opiskelijataulukossa on 100 attribuuttia, meidän on kirjoitettava 100 riviä while-silmukkaan tietojen hakemiseksi, ja myös paikkamerkkien täyttäminen voi viedä useita rivejä.


Ratkaisu:DBUtils voi auttaa kehittäjiä tietojen kapseloinnissa (tulosjoukkojen kartoittaminen Java-objekteihin).

Käyttövaiheet:

① Tuo riippuvuudet pom.xml:ssä

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

② Kirjoita koodi

  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. }

Tässä vaiheessa paikkamerkkien täyttäminen ja tulosjoukon poistaminen voidaan suorittaa kahdella koodirivillä.

yksityiskohta:

① Kyselymenetelmän on läpäistävä 4 parametria:

Yhteysobjekti

SQL-lause

ResultSetHandler-rajapinnan toteutusluokkaobjekti (muunnetun objektin tyypin tulee olla Student.class)

Parametrit paikkamerkkien täyttämiseksi

② ResultSetHandler-liitäntää käytetään tulosjoukkojen käsittelyyn. Se voi muuntaa kyselyn kohteena olevat tulosjoukot Java-objekteiksi.

BeanHandlerYhdistä tulosjoukko Java-objektiksi (kuten opiskelija-objektiksi)
BeanListHandler Yhdistä tulosjoukko List-kokoelmaksi (kuten: List<Student > )
MapHandler

Yhdistä tulosjoukko Karttakokoelmaobjektiksi

(eli: kartta<String,Object> avain: attribuutin nimi: attribuutin arvo)

MapListHandler Yhdistä tulosjoukko MapList-kokoelmaan (eli: List <Map<<String,Object> &gt;)

③ Paikkamerkkiin täytettävä parametri on muuttuva parametri, joten mikä tahansa määrä parametreja voidaan välittää vastaamaan käyttäjien erilaisia ​​tarpeita.

④ Muunnetussa objektiluokassa (Student class) tulee olla parametriton konstruktori, muuten ohjelma ilmoittaa virheestä.

syy:Alin kerros löytää tämän luokan Student.classin kautta ja sitten sen kauttaheijastusmekanismiEtsi tämän luokan parametriton konstruktori ja luo sen objekti.

⑤ Luokan attribuutin nimen on oltava täsmälleen sama kuin tietokantataulukon kentän nimi.

Koska objektin luomisen jälkeen, kun objektin ominaisuuksille annetaan arvoja tulosjoukon perusteella, haku ja määritys suoritetaan nimen perusteella.

11. Kolmikerroksinen MVC-arkkitehtuuri

Mikä on MVC?

  • Malli: malli (palvelu, dao, entiteetti)
  • Näytä: Näytä (jsp, html, sovellusohjelma)
  • Ohjain: Ohjain (servlet, Hander, Action)

Kun pyyntö saapuu JavaWeb-sovellukseen, Controller vastaanottaa pyynnön, suorittaa liiketoimintalogiikkakäsittelyn ja palauttaa lopuksi tuloksen käyttäjälle (View + Model).

1. Esittely

Alkuvuosina verkkosovelluksia käytettäessä käyttäjät pääsivät suoraan ohjauskerrokseen, ja ohjauskerros pystyi suoraan käyttämään tietokantaa:

servlet--CRUD (lisää, poista, muokkaa)--&gt; tietokanta

Servlet-koodissa: pyyntöjen, vastausten, näkymähyppyjen, JDBC-käsittelyn, yrityskoodin käsittelyn ja logiikkakoodin käsittelyn

Haitat:Ohjelma on erittäin turvonnut, eikä se edistä ylläpitoa

ratkaisu: Ei ole mitään, mitä toisen kerroksen lisääminen ei ratkaise, jos on, lisää toinen kerros!

2. mvc kolmikerroksinen arkkitehtuuri

Malli

  • Liiketoiminnan käsittely: liiketoimintalogiikka (palvelu)
  • Tietojen pysyvyyskerros: CRUD (DAO-datan pysyvyysobjekti)

näkymä

  • näyttää tiedot
  • Anna linkki Servlet-pyynnön aloittamiseksi (a, lomake, img...)

Ohjain (servlet)

  • Vastaanota käyttäjän pyyntö: (pyyntö, pyyntöparametrit, istuntotiedot)
  • Luovuta se yritystasolle vastaavan koodin käsittelemiseksi
  • Ohjausnäkymän hyppy

Otetaan esimerkiksi käyttäjän ja järjestelmänvalvojan kirjautuminen:

Ohjaintaso:

  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. }

Palvelukerros:

  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. }

Dao/Arkistotaso:

  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. }