2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
JavaWeb (1: Perustiedot ja ympäristön rakentaminen)https://blog.csdn.net/xpy2428507302/article/details/140365130?spm=1001.2014.3001.5501JavaWeb (2: Servlet ja Jsp, kuuntelija ja suodatin)
https://blog.csdn.net/xpy2428507302/article/details/140365159?spm=1001.2014.3001.5501
Sisällysluettelo
11. Kolmikerroksinen MVC-arkkitehtuuri
2. mvc kolmikerroksinen arkkitehtuuri
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.
① Luo tietokantataulukko
- 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;
② Tuo tietokantariippuvuudet
- <!--mysql的驱动-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.31</version>
- </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
- 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 | protokollaa |
mysql | aliprotokolla |
localhost: 3306 | isäntä: portti |
xxx | tietokanta |
Kuinka kirjoittaa yleisesti käytettyjä tietokannan URL-osoitteita:
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ä |
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.
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 |
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.
Statementin käytössä kehitystyössä on kaksi ongelmaa:
① Merkkijonoja on jaettava usein, ja virheprosentti on korkea
- String username = "zhangsan";
- String password = "123";
- String sql = "select * from users where name='"+username+"' and password='"+password+"'";
- 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.
- 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();
- }
- }
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.
- 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();
- }
- }
operaation tulos:
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
- /*创建账户表*/
- 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);
② Simuloi liiketoimintaskenaariota, kun siirto onnistuu
- //失败后让数据库自动回滚事务
- 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();
- }
- }
- }
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.
- 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();
- }
- }
- }
Puhelutapaus, kuten: lisää käyttäjä
-
- 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-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--> 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.
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ä
- <dependency>
- <groupId>com.mchange</groupId>
- <artifactId>c3p0</artifactId>
- <version>0.9.5.2</version>
- </dependency>
② Kirjoita koodi
- 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();
- }
- }
- }
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:
- <?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>
③ Kirjoita Java-ohjelma
- 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();
- }
- }
- }
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:
- 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;
- }
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ä
- <dependency>
- <groupId>commons-dbutils</groupId>
- <artifactId>commons-dbutils</artifactId>
- <version>1.6</version>
- </dependency>
② Kirjoita koodi
- 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;
- }
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.
BeanHandler | Yhdistä 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> >) |
③ 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.
Mikä on MVC?
Kun pyyntö saapuu JavaWeb-sovellukseen, Controller vastaanottaa pyynnön, suorittaa liiketoimintalogiikkakäsittelyn ja palauttaa lopuksi tuloksen käyttäjälle (View + Model).
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)--> 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!
Malli
näkymä
Ohjain (servlet)
Otetaan esimerkiksi käyttäjän ja järjestelmänvalvojan kirjautuminen:
Ohjaintaso:
- @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");
- }
- }
-
- }
Palvelukerros:
- 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/Arkistotaso:
- 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;
- }
- }