<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # MySQL Java 教程 > 原文: [http://zetcode.com/db/mysqljava/](http://zetcode.com/db/mysqljava/) 這是 MySQL 數據庫的 Java 教程。 它涵蓋了使用 JDBC 進行 Java 中 MySQL 編程的基礎。 ZetCode 擁有用于 MySQL Java 的完整電子書: [MySQL Java 編程電子書](/ebooks/mysqljava/)。 [Tweet](https://twitter.com/share) 在本教程中,我們使用 MySQL Connector/J 驅動程序。 它是 MySQL 的官方 JDBC 驅動程序。 這些示例是在 Ubuntu Linux 上創建和測試的。 您可能還需要查看 [Java 教程](/lang/java/), [PostgreSQL Java 教程](/db/postgresqljavatutorial/), [Apache Derby 教程](/db/apachederbytutorial/), [MySQL 教程](/databases/mysqltutorial/)或 [Spring JdbcTemplate ZetCode 的教程](/db/jdbctemplate/)。 ## JDBC _JDBC_ 是 Java 編程語言的 API,用于定義客戶端如何訪問數據庫。 它提供了查詢和更新數據庫中數據的方法。 JDBC 面向關系數據庫。 從技術角度來看,API 是`java.sql`包中的一組類。 要將 JDBC 與特定數據庫一起使用,我們需要該數據庫的 JDBC 驅動程序。 JDBC 是 Java 數據庫編程的基石。 今天,它被認為是非常底層的,并且容易出錯。 創建了諸如 MyBatis 或`JdbcTemplate`之類的解決方案來減輕 JDBC 編程的負擔。 但是,實際上,這些解決方案仍然使用 JDBC。 JDBC 是 Java Standard Edition 平臺的一部分。 JDBC 管理以下三個主要的編程活動: * 連接到數據庫; * 向數據庫發送查詢和更新語句; * 檢索和處理從數據庫接收到的結果以響應查詢。 ## MySQL Connector/J 為了以 Java 連接到 MySQL,MySQL 提供了 MySQL Connector/J,它是實現 JDBC API 的驅動程序。 MySQL Connector/J 是 JDBC Type 4 驅動程序。 Type 4 表示驅動程序是 MySQL 協議的純 Java 實現,并且不依賴 MySQL 客戶端庫。 在本教程中,我們使用 MySQL Connector/J 5.1.41,它是 5.1 生產分支的維護版本。 ## 連接字符串 使用連接字符串定義數據庫連接。 它包含諸如數據庫類型,數據庫名稱,服務器名稱和端口號之類的信息。 它還可能包含用于配置的其他鍵/值對。 每個數據庫都有其自己的連接字符串格式。 以下是 MySQL 連接字符串的語法: ```java jdbc:mysql://[host1][:port1][,[host2][:port2]]...[/[database]] [?propertyName1=propertyValue1[&propertyName2=propertyValue2]...] ``` 可以為服務器故障轉移設置指定多個主機。 方括號中的項目是可選的。 如果未指定主機,則主機名默認為`localhost`。 如果未指定主機端口,則默認為 MySQL 服務器的默認端口號 3306。 ```java jdbc:mysql://localhost:3306/testdb?useSSL=false ``` 這是一個 MySQL 連接字符串的示例。 `jdbc:mysql://`被稱為子協議,對于 MySQL 來說是恒定的。 我們在 MySQL 標準端口 3306 上連接到`localhost`。數據庫名稱為`testdb`。 其他鍵/值對在問號字符(`?`)之后。 `useSSL=false`告訴 MySQL,將沒有安全連接。 ## 關于 MySQL 數據庫 MySQL 是領先的開源數據庫管理系統。 它是一個多用戶,多線程的數據庫管理系統。 MySQL 在網絡上特別流行。 它是由 Linux,Apache,MySQL 和 PHP 組成的非常流行的 _LAMP_ 平臺的一部分。 目前,MySQL 由 Oracle 擁有。 在大多數重要的 OS 平臺上都可以使用 MySQL 數據庫。 它可以在 BSD Unix,Linux,Windows 或 Mac OS 上運行。 維基百科和 YouTube 使用 MySQL。 這些站點每天管理數百萬個查詢。 MySQL 有兩個版本:MySQL 服務器系統和 MySQL 嵌入式系統。 ## 設置 MySQL 在本節中,我們將安裝 MySQL 服務器,創建`testdb`數據庫和測試用戶。 ```java $ sudo apt-get install mysql-server ``` 此命令將安裝 MySQL 服務器和其他各種包。 在安裝包時,提示我們輸入 MySQL 根帳戶的密碼。 接下來,我們將創建一個新的數據庫用戶和一個新的數據庫。 我們使用`mysql`客戶端。 ```java $ sudo service mysql status mysql start/running, process 5129 ``` 我們檢查 MySQL 服務器是否正在運行。 如果沒有,我們需要啟動服務器。 在 Ubuntu Linux 上,可以使用`sudo service mysql start`命令來完成。 ```java $ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 43 Server version: 5.7.21-0ubuntu0.16.04.1 (Ubuntu) Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | +--------------------+ 2 rows in set (0.00 sec) ``` 我們使用 mysql 監視器客戶端應用連接到服務器。 我們使用根帳戶連接到數據庫。 我們用`SHOW DATABASES`語句顯示所有可用的數據庫。 ```java mysql> CREATE DATABASE testdb; Query OK, 1 row affected (0.02 sec) ``` 我們創建一個新的`testdb`數據庫。 在整個教程中,我們將使用此數據庫。 ```java mysql> CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'test623'; Query OK, 0 rows affected (0.00 sec) mysql> USE testdb; Database changed mysql> GRANT ALL ON testdb.* TO 'testuser'@'localhost'; Query OK, 0 rows affected (0.00 sec) mysql> quit; Bye ``` 我們創建一個新的數據庫用戶。 我們為該用戶授予`testdb`數據庫所有表的所有特權。 ## Maven 文件 我們使用以下 Maven 文件: `pom.xml` ```java <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zetcode</groupId> <artifactId>AppName</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.6.0</version> <configuration> <mainClass>com.zetcode.AppName</mainClass> <cleanupDaemonThreads>false</cleanupDaemonThreads> </configuration> </plugin> </plugins> </build> <name>AppName</name> </project> ``` POM 文件具有 MySQL 驅動程序的依賴關系。 我們還包括用于執行 Maven Java 程序的`exec-maven-plugin`。 在`<mainClass></mainClass>`標簽之間,我們提供了應用的全名。 ## Java MySQL 版本 如果以下程序運行正常,則我們已安裝一切正常。 我們檢查 MySQL 服務器的版本。 `JdbcMySQLVersion.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcMySQLVersion { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String query = "SELECT VERSION()"; try (Connection con = DriverManager.getConnection(url, user, password); Statement st = con.createStatement(); ResultSet rs = st.executeQuery(query)) { if (rs.next()) { System.out.println(rs.getString(1)); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcMySQLVersion.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 我們連接到數據庫并獲取有關 MySQL 服務器的一些信息。 ```java String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; ``` 這是 MySQL 數據庫的連接 URL。 每個驅動程序對于 URL 都有不同的語法。 在本例中,我們提供了主機,端口和數據庫名稱。 ```java try (Connection con = DriverManager.getConnection(url, user, password); Statement st = con.createStatement(); ResultSet rs = st.executeQuery(query)) { ``` 我們使用連接 URL,用戶名和密碼建立與數據庫的連接。 通過`getConnection()`方法建立連接。 連接對象的`createStatement()`方法創建一個`Statement`對象,用于將 SQL 語句發送到數據庫。 連接對象的`executeQuery()`方法執行給定的 SQL 語句,該語句返回單個`ResultSet`對象。 `ResultSet`是由特定 SQL 語句返回的數據表。 `try-with-resources`語法可確保最終清除資源。 ```java if (result.next()) { System.out.println(result.getString(1)); } ``` `ResultSet`對象維護一個游標,該游標指向其當前數據行。 最初,光標位于第一行之前。 `next()`方法將光標移動到下一行。 如果沒有剩余的行,則該方法返回`false`。 `getString()`方法檢索指定列的值。 第一列的索引為 1。 ```java } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcMySQLVersion.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } ``` 如果發生異常,我們將記錄錯誤消息。 對于此控制臺示例,該消息顯示在終端中。 ```java $ mvn exec:java -q 5.7.21-0ubuntu0.16.04.1 ``` 我們從命令行運行程序。 Manen 的`-q`選項在安靜模式下運行 Maven。 即我們只看到錯誤消息。 ## 創建和填充表 接下來,我們將創建數據庫表并用數據填充它們。 這些表將在本教程中使用。 `mysql_tables.sql` ```java USE testdb; DROP TABLE IF EXISTS Books, Authors, Testing, Images; CREATE TABLE Authors(Id BIGINT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(100)); CREATE TABLE Books(Id BIGINT PRIMARY KEY AUTO_INCREMENT, AuthorId BIGINT, Title VARCHAR(100), FOREIGN KEY(AuthorId) REFERENCES Authors(Id) ON DELETE CASCADE); CREATE TABLE Testing(Id INT); CREATE TABLE Images(Id INT PRIMARY KEY AUTO_INCREMENT, Data MEDIUMBLOB); INSERT INTO Authors(Id, Name) VALUES(1, 'Jack London'); INSERT INTO Authors(Id, Name) VALUES(2, 'Honore de Balzac'); INSERT INTO Authors(Id, Name) VALUES(3, 'Lion Feuchtwanger'); INSERT INTO Authors(Id, Name) VALUES(4, 'Emile Zola'); INSERT INTO Authors(Id, Name) VALUES(5, 'Truman Capote'); INSERT INTO Books(Id, AuthorId, Title) VALUES(1, 1, 'Call of the Wild'); INSERT INTO Books(Id, AuthorId, Title) VALUES(2, 1, 'Martin Eden'); INSERT INTO Books(Id, AuthorId, Title) VALUES(3, 2, 'Old Goriot'); INSERT INTO Books(Id, AuthorId, Title) VALUES(4, 2, 'Cousin Bette'); INSERT INTO Books(Id, AuthorId, Title) VALUES(5, 3, 'Jew Suess'); INSERT INTO Books(Id, AuthorId, Title) VALUES(6, 4, 'Nana'); INSERT INTO Books(Id, AuthorId, Title) VALUES(7, 4, 'The Belly of Paris'); INSERT INTO Books(Id, AuthorId, Title) VALUES(8, 5, 'In Cold blood'); INSERT INTO Books(Id, AuthorId, Title) VALUES(9, 5, 'Breakfast at Tiffany'); ``` SQL 命令創建四個數據庫表:`Authors`,`Books`,`Testing`和`Images`。 這些表是 InnoDB 類型的。 InnoDB 數據庫支持外鍵約束和事務。 我們將外鍵約束放置在`Books`表的`AuthorId`列上。 我們用初始數據填充`Authors`和`Books`表。 ```java mysql> source mysql_tables.sql Query OK, 0 rows affected (0.07 sec) Query OK, 0 rows affected (0.12 sec) Query OK, 1 row affected (0.04 sec) ... ``` 我們使用`source`命令執行`tables.sql`腳本。 ## Java MySQL 預備語句 現在,我們將以預備語句來關注自己。 在編寫預備語句時,我們使用占位符,而不是直接將值寫入語句中。 預準備的語句可提高安全性和性能。 在 Java 中,`PreparedStatement`是代表預編譯的 SQL 語句的對象。 `JdbcPrepared.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcPrepared { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String author = "Trygve Gulbranssen"; String sql = "INSERT INTO Authors(Name) VALUES(?)"; try (Connection con = DriverManager.getConnection(url, user, password); PreparedStatement pst = con.prepareStatement(sql)) { pst.setString(1, author); pst.executeUpdate(); System.out.println("A new author has been inserted"); } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcPrepared.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 我們將新作者添加到`Authors`表中。 ```java try (Connection con = DriverManager.getConnection(url, user, password); PreparedStatement pst = con.prepareStatement(sql)) { ``` 在這里,我們創建一個預備語句。 在編寫預備語句時,我們使用占位符,而不是直接將值寫入語句中。 預備語句更快,并且可以防止 SQL 注入攻擊。 `?`是一個占位符,稍后將被填充。 ```java pst.setString(1, author); ``` 值綁定到占位符。 ```java pst.executeUpdate(); ``` 執行預備語句。 當我們不希望返回任何數據時,我們使用語句對象的`executeUpdate()`方法。 這是當我們創建數據庫或執行`INSERT`,`UPDATE`,`DELETE`語句時。 ```java $ mvn exec:java -q A new author has been inserted mysql> select * from Authors; +----+--------------------+ | Id | Name | +----+--------------------+ | 1 | Jack London | | 2 | Honore de Balzac | | 3 | Lion Feuchtwanger | | 4 | Emile Zola | | 5 | Truman Capote | | 6 | Trygve Gulbranssen | +----+--------------------+ 6 rows in set (0.00 sec) ``` 我們在表中插入了一位新作者。 ## 測試 MySQL 預備和非預備的語句 對于以下兩個示例,我們將使用`Testing`表。 我們將執行一條普通語句和一條準備語句 5000 次。 我們檢查執行時間是否有差異。 `JdbcNotPreparedTesting.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcNotPreparedTesting { public static void main(String[] args) { String cs = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; try (Connection con = DriverManager.getConnection(cs, user, password); Statement st = con.createStatement()) { for (int i = 1; i <= 5000; i++) { String sql = "INSERT INTO Testing(Id) VALUES(" + 2 * i + ")"; st.executeUpdate(sql); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcNotPreparedTesting.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 第一個示例使用普通的`Statement`對象。 ```java for (int i = 1; i <= 5000; i++) { String sql = "INSERT INTO Testing(Id) VALUES(" + 2 * i + ")"; st.executeUpdate(sql); } ``` 我們建立查詢并執行 5000 次。 ```java $ time mvn exec:java -q real 4m14.716s user 0m6.820s sys 0m0.404s ``` 完成 5000 次插入需要 4.14 分鐘。 `JdbcPreparedTesting.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcPreparedTesting { public static void main(String[] args) { String cs = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String sql = "INSERT INTO Testing(Id) VALUES(?)"; try (Connection con = DriverManager.getConnection(cs, user, password); PreparedStatement pst = con.prepareStatement(sql)) { for (int i = 1; i <= 5000; i++) { pst.setInt(1, i * 2); pst.executeUpdate(); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcPreparedTesting.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 現在,我們使用`PreparedStatement`執行相同的任務。 ```java try (Connection con = DriverManager.getConnection(cs, user, password); PreparedStatement pst = con.prepareStatement(sql)) { ``` 我們使用`prepareStatement()`方法創建預備語句。 ```java for (int i = 1; i <= 5000; i++) { pst.setInt(1, i * 2); pst.executeUpdate(); } ``` 我們將一個值綁定到預備語句,并在循環中執行數千次。 ```java $ time mvn exec:java -q real 3m53.962s user 0m6.280s sys 0m0.380s ``` 現在花了 3.53 分鐘完成了 5000 次插入。 我們節省了 20 秒。 ## Java MySQL 檢索數據 接下來,我們將展示如何從數據庫表中檢索數據。 我們從`Authors`表中獲取所有數據。 `JdbcRetrieve.java` ```java package com.zetcode; import java.sql.PreparedStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcRetrieve { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String query = "SELECT * FROM Authors"; try (Connection con = DriverManager.getConnection(url, user, password); PreparedStatement pst = con.prepareStatement(query); ResultSet rs = pst.executeQuery()) { while (rs.next()) { System.out.print(rs.getInt(1)); System.out.print(": "); System.out.println(rs.getString(2)); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcRetrieve.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 我們從`Authors`表中獲取所有作者并將其打印到控制臺。 ```java String query = "SELECT * FROM Authors"; try (Connection con = DriverManager.getConnection(url, user, password); PreparedStatement pst = con.prepareStatement(query); ResultSet rs = pst.executeQuery()) { ``` 我們執行一個查詢,該查詢從`Authors`表中選擇所有列。 我們使用`executeQuery()`方法。 該方法執行給定的 SQL 語句,該語句返回單個`ResultSet`對象。 `ResultSet`是 SQL 查詢返回的數據表。 ```java while (rs.next()) { System.out.print(rs.getInt(1)); System.out.print(": "); System.out.println(rs.getString(2)); } ``` `next()`方法將光標移至下一條記錄。 當結果集中沒有更多行時,它將返回`false`。 `getInt()`和`getString()`方法檢索此`ResultSet`對象當前行中指定列的值,作為 Java 編程語言的`int`和`String`。 ```java $ mvn exec:java -q 1: Jack London 2: Honore de Balzac 3: Lion Feuchtwanger 4: Emile Zola 5: Truman Capote 6: Trygve Gulbranssen ``` 我們執行程序; 我們在控制臺上印有作者的 ID 和姓名。 ## 屬性 通常的做法是將配置數據放在程序外部的單獨文件中。 這樣程序員可以更加靈活。 我們可以更改用戶,密碼或連接 URL,而無需重新編譯程序。 它在需要大量測試,調試,保護數據等的動態環境中特別有用。 在 Java 中,`Properties`是為此經常使用的類。 該類用于輕松讀取和保存鍵/值屬性。 `db.properties` ```java db.url=jdbc:mysql://localhost:3306/testdb?useSSL=false db.user=testuser db.passwd=test623 ``` 我們有一個`db.properties`文件,其中有三個鍵/值對。 這些是在程序執行期間動態加載的。 `JdbcProperties.java` ```java package com.zetcode; import java.io.FileInputStream; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.PreparedStatement; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcProperties { private static Properties getConnectionData() { Properties props = new Properties(); String fileName = "src/main/resources/db.properties"; try (FileInputStream in = new FileInputStream(fileName)) { props.load(in); } catch (IOException ex) { Logger lgr = Logger.getLogger(JdbcProperties.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } return props; } public static void main(String[] args) { Properties props = getConnectionData(); String url = props.getProperty("db.url"); String user = props.getProperty("db.user"); String passwd = props.getProperty("db.passwd"); String query = "SELECT * FROM Authors"; try (Connection con = DriverManager.getConnection(url, user, passwd); PreparedStatement pst = con.prepareStatement(query); ResultSet rs = pst.executeQuery()) { while (rs.next()) { System.out.print(rs.getInt(1)); System.out.print(": "); System.out.println(rs.getString(2)); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcProperties.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 我們連接到`testdb`數據庫,并將`Authors`表的內容打印到控制臺。 這次,我們從文件加載連接屬性。 他們沒有在程序中硬編碼。 ```java Properties props = new Properties(); String fileName = "src/main/resources/db.properties"; try (FileInputStream in = new FileInputStream(fileName)) { props.load(in); } catch (IOException ex) { Logger lgr = Logger.getLogger(JdbcProperties.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } ``` 創建`Properties`類。 數據是從名為`db.properties`的文件中加載的,其中包含我們的配置數據。 ```java String url = props.getProperty("db.url"); String user = props.getProperty("db.user"); String passwd = props.getProperty("db.passwd"); ``` 使用`getProperty()`方法檢索這些值。 ## Java MySQL 數據源 在此示例中,我們使用數據源連接到數據庫。 數據源的使用可以提高應用的性能和可伸縮性。 與`DriverManager`相比,使用數據源具有多個優點:增強了可移植性,連接池和分布式事務。 `MysqlDataSource`是用于創建數據源的類。 `db.properties` ```java # mysql properties mysql.driver=com.mysql.jdbc.Driver mysql.url=jdbc:mysql://localhost:3306/testdb?useSSL=false mysql.username=testuser mysql.password=test623 ``` 是 MySQL 數據庫的屬性。 `ComLineDSEx.java` ```java package com.zetcode; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import java.io.FileInputStream; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.PreparedStatement; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; public class ComLineDSEx { public static MysqlDataSource getMySQLDataSource() { Properties props = new Properties(); String fileName = "src/main/resources/db.properties"; try (FileInputStream fis = new FileInputStream(fileName)) { props.load(fis); } catch (IOException ex) { Logger lgr = Logger.getLogger(ComLineDSEx.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } MysqlDataSource ds = new MysqlDataSource(); ds.setURL(props.getProperty("mysql.url")); ds.setUser(props.getProperty("mysql.username")); ds.setPassword(props.getProperty("mysql.password")); return ds; } public static void main(String[] args) { MysqlDataSource ds = getMySQLDataSource(); String query = "SELECT VERSION()"; try (Connection con = ds.getConnection(); PreparedStatement pst = con.prepareStatement(query); ResultSet rs = pst.executeQuery()) { if (rs.next()) { String version = rs.getString(1); System.out.println(version); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(ComLineDSEx.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 在此示例中,我們使用數據源連接到數據庫。 ```java String fileName = "src/main/resources/db.properties"; try (FileInputStream fis = new FileInputStream(fileName)) { props.load(fis); } catch (IOException ex) { Logger lgr = Logger.getLogger(ComLineDSEx.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } ``` 從`db.properties`文件中讀取數據庫屬性。 ```java MysqlDataSource ds = new MysqlDataSource(); ds.setURL(props.getProperty("mysql.url")); ds.setUser(props.getProperty("mysql.username")); ds.setPassword(props.getProperty("mysql.password")); ``` 創建`MysqlDataSource`并設置數據源屬性。 ```java try (Connection con = ds.getConnection(); PreparedStatement pst = con.prepareStatement(query); ResultSet rs = pst.executeQuery()) { ``` 連接對象是從數據源創建的。 ## Java MySQL 多條語句 可以在一個查詢中執行多個 SQL 語句。 必須將`allowMultiQueries`設置為啟用 MySQL 中的多個語句。 `JdbcMulStat.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class JdbcMulStat { public static void main(String[] args) throws SQLException { String cs = "jdbc:mysql://localhost:3306/" + "testdb?allowMultiQueries=true&useSSL=false"; String user = "testuser"; String password = "test623"; String query = "SELECT Id, Name FROM Authors WHERE Id=1;" + "SELECT Id, Name FROM Authors WHERE Id=2;" + "SELECT Id, Name FROM Authors WHERE Id=3"; try (Connection con = DriverManager.getConnection(cs, user, password); PreparedStatement pst = con.prepareStatement(query);) { boolean isResult = pst.execute(); do { try (ResultSet rs = pst.getResultSet()) { while (rs.next()) { System.out.print(rs.getInt(1)); System.out.print(": "); System.out.println(rs.getString(2)); } isResult = pst.getMoreResults(); } } while (isResult); } } } ``` 在代碼示例中,我們從`Authors`表中檢索三行。 我們使用三個`SELECT`語句來獲取三行。 ```java String cs = "jdbc:mysql://localhost:3306/" + "testdb?allowMultiQueries=true&useSSL=false"; ``` 通過將`allowMultiQueries`參數設置為`true`,我們可以在數據庫 URL 中啟用多個語句查詢。 ```java String query = "SELECT Id, Name FROM Authors WHERE Id=1;" + "SELECT Id, Name FROM Authors WHERE Id=2;" + "SELECT Id, Name FROM Authors WHERE Id=3"; ``` 在這里,我們有一個包含多個語句的查詢。 語句用分號分隔。 ```java boolean isResult = pst.execute(); ``` 我們調用已預備語句對象的`execute()`方法。 該方法返回一個布爾值,該布爾值指示第一個結果是否為`ResultSet`對象。 使用`getMoreResults()`方法調用后續結果。 ```java do { try (ResultSet rs = pst.getResultSet()) { while (rs.next()) { System.out.print(rs.getInt(1)); System.out.print(": "); System.out.println(rs.getString(2)); } isResult = pst.getMoreResults(); } } while (isResult); ``` 結果的處理在`do while`循環內完成。 通過`getResultSet()`方法調用檢索`ResultSet`。 為了找出是否還有其他結果,我們調用`getMoreResults()`方法。 ```java $ mvn exec:java -q 1: Jack London 2: Honore de Balzac 3: Lion Feuchtwanger ``` 這是示例的輸出。 前三行是從`Authors`表中檢索的。 ## Java MySQL 列標題 下面的示例顯示如何使用數據庫表中的數據打印列標題。 我們將列名稱稱為元數據。 元數據是有關數據庫中核心數據的數據。 `JdbcColumnHeaders.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcColumnHeaders { public static void main(String[] args) { String cs = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String query = "SELECT Name, Title From Authors, " + "Books WHERE Authors.Id=Books.AuthorId"; try (Connection con = DriverManager.getConnection(cs, user, password); PreparedStatement pst = con.prepareStatement(query); ResultSet rs = pst.executeQuery()) { ResultSetMetaData meta = rs.getMetaData(); String colname1 = meta.getColumnName(1); String colname2 = meta.getColumnName(2); String header = String.format("%-21s%s", colname1, colname2); System.out.println(header); while (rs.next()) { String row = String.format("%-21s", rs.getString(1)); System.out.print(row); System.out.println(rs.getString(2)); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcColumnHeaders.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 在此程序中,我們從`Authors`表中選擇作者,并從`Books`表中選擇他們的書。 我們打印結果集中返回的列的名稱。 輸出已格式化。 ```java String query = "SELECT Name, Title From Authors, " + "Books WHERE Authors.Id=Books.AuthorId"; ``` 這是將作者與他們的書聯系在一起的 SQL 語句。 ```java ResultSetMetaData meta = rs.getMetaData(); ``` 要獲取列名,我們需要獲取`ResultSetMetaData`。 它是一個對象,可用于獲取有關`ResultSet`對象中列的類型和屬性的信息。 ```java String colname1 = meta.getColumnName(1); String colname2 = meta.getColumnName(2); ``` 從獲得的元數據中,我們獲得列名。 ```java String header = String.format("%-21s%s", colname1, colname2); System.out.println(header); ``` 我們將列名稱打印到控制臺。 ```java while (rs.next()) { String row = String.format("%-21s", rs.getString(1)); System.out.print(row); System.out.println(rs.getString(2)); } ``` 我們將數據打印到控制臺。 第一列為 21 個字符,并在左側對齊。 ```java $ mvn exec:java -q NAME Title Jack London Call of the Wild Jack London Martin Eden Honore de Balzac Old Goriot Honore de Balzac Cousin Bette Lion Feuchtwanger Jew Suess Emile Zola Nana Emile Zola The Belly of Paris Truman Capote In Cold blood Truman Capote Breakfast at Tiffany ``` 這是程序的輸出。 ## MySQL Java 自動生成的鍵 MySQL 的`AUTO_INCREMENT`屬性為新行生成唯一的 ID。 以下示例說明了如何使用 JDBC 檢索自動生成的鍵值。 `JdbcAutoGenKey.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcAutoGenKey { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String author = "Oscar Wilde"; String sql = "INSERT INTO Authors(Name) VALUES(?)"; try (Connection con = DriverManager.getConnection(url, user, password); PreparedStatement pst = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { pst.setString(1, author); pst.executeUpdate(); try (ResultSet rs = pst.getGeneratedKeys()) { if (rs.first()) { System.out.printf("The ID of new author: %d", rs.getLong(1)); } } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcAutoGenKey.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 在該示例中,我們向表中添加了一個新作者,其主鍵由 MySQL 自動遞增。 我們檢索生成的 ID。 ```java try (Connection con = DriverManager.getConnection(url, user, password); PreparedStatement pst = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { ``` 第一步,我們必須將`Statement.RETURN_GENERATED_KEYS`傳遞給`prepareStatement()`方法。 ```java try (ResultSet rs = pst.getGeneratedKeys()) { ``` 然后,我們使用`getGeneratedKeys()`方法檢索生成的鍵。 ```java if (rs.first()) { System.out.printf("The ID of new author: %d", rs.getLong(1)); } ``` 由于我們只有一個插入語句,因此我們使用`first()`導航到該值。 ```java $ mvn exec:java -q The ID of new author: 7 ``` 這是一個示例輸出。 ## MySQL Java 編寫圖像 有些人喜歡將其圖像放入數據庫中,有些人則希望將其保留在文件系統中以供其應用使用。 當我們處理大量圖像時,會出現技術難題。 圖像是二進制數據。 MySQL 數據庫具有一種特殊的數據類型來存儲稱為`BLOB`(二進制大對象)的二進制數據。 對于此示例,我們使用`Images`表。 `JdbcWriteImage.java` ```java package com.zetcode; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcWriteImage { public static void main(String[] args) { String cs = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String sql = "INSERT INTO Images(Data) VALUES(?)"; try (Connection con = DriverManager.getConnection(cs, user, password); PreparedStatement pst = con.prepareStatement(sql)) { File myFile = new File("src/main/resources/tree.png"); try (FileInputStream fin = new FileInputStream(myFile)) { pst.setBinaryStream(1, fin, (int) myFile.length()); pst.executeUpdate(); } catch (IOException ex) { Logger lgr = Logger.getLogger(JdbcWriteImage.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcWriteImage.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 在前面的示例中,我們從當前工作目錄中讀取 PNG 圖像,并將其插入`Images`表中。 ```java String sql = "INSERT INTO Images(Data) VALUES(?)"; ``` 這是插入圖像的 SQL。 ```java File myFile = new File("src/main/resources/tree.png"); try (FileInputStream fin = new FileInputStream(myFile)) { ``` 我們為圖像文件創建一個`File`對象。 要從該文件讀取字節,我們創建一個`FileInputStream`對象。 ```java pst.setBinaryStream(1, fin, (int) myFile.length()); ``` 二進制流設置為預備語句。 `setBinaryStream()`方法的參數是要綁定的參數索引,輸入流和流中的字節數。 ```java pst.executeUpdate(); ``` 我們執行該語句。 ## MySQL Java 讀取圖像 在前面的示例中,我們已將圖像插入數據庫表中。 現在,我們將從表中讀取圖像。 `JdbcReadImage.java` ```java package com.zetcode; import java.io.FileOutputStream; import java.io.IOException; import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcReadImage { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String query = "SELECT Data FROM Images LIMIT 1"; try (Connection con = DriverManager.getConnection(url, user, password); PreparedStatement pst = con.prepareStatement(query); ResultSet result = pst.executeQuery()) { if (result.next()) { String fileName = "src/main/resources/tree.png"; try (FileOutputStream fos = new FileOutputStream(fileName)) { Blob blob = result.getBlob("Data"); int len = (int) blob.length(); byte[] buf = blob.getBytes(1, len); fos.write(buf, 0, len); } catch (IOException ex) { Logger lgr = Logger.getLogger(JdbcReadImage.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcReadImage.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 我們從圖片表中讀取了一張圖片。 ```java String query = "SELECT Data FROM Images LIMIT 1"; ``` 我們從表中選擇一條記錄。 ```java String fileName = "src/main/resources/tree.png"; try (FileOutputStream fos = new FileOutputStream(fileName)) { ``` 創建`FileOutputStream`對象以寫入文件。 它旨在寫入原始字節流,例如圖像數據。 ```java Blob blob = result.getBlob("Data"); ``` 我們通過調用`getBlob()`方法從`Data`列中獲取圖像數據。 ```java int len = (int) blob.length(); ``` 我們計算出斑點數據的長度。 換句話說,我們得到字節數。 ```java byte[] buf = blob.getBytes(1, len); ``` `getBytes()`方法以字節數組的形式檢索 Blob 對象的所有字節。 ```java fos.write(buf, 0, len); ``` 字節被寫入輸出流。 該映像在文件系統上創建。 ## 事務支持 事務是針對一個或多個數據庫中數據的數據庫操作的基本單位。 事務中所有 SQL 語句的影響可以全部提交給數據庫,也可以全部回滾。 MySQL 數據庫具有不同類型的存儲引擎。 最常見的是 MyISAM 和 InnoDB 引擎。 在數據安全性和數據庫速度之間需要權衡。 MyISAM 表的處理速度更快,并且不支持事務。 另一方面,InnoDB 表可以更安全地防止數據丟失。 它們支持事務,并且處理速度較慢。 `JdbcTransaction.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcTransaction { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; try (Connection con = DriverManager.getConnection(url, user, password)) { try (Statement st = con.createStatement()) { con.setAutoCommit(false); st.executeUpdate("UPDATE Authors SET Name = 'Leo Tolstoy'" + "WHERE Id = 1"); st.executeUpdate("UPDATE Books SET Title = 'War and Peace'" + "WHERE Id = 1"); st.executeUpdate("UPDATE Books SET Titl = 'Anna Karenina'" + "WHERE Id = 2"); con.commit(); } catch (SQLException ex) { try { con.rollback(); } catch (SQLException ex1) { Logger lgr = Logger.getLogger(JdbcTransaction.class.getName()); lgr.log(Level.WARNING, ex1.getMessage(), ex1); } Logger lgr = Logger.getLogger(JdbcTransaction.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } catch (SQLException ex) { Logger.getLogger(JdbcTransaction.class.getName()).log( Level.SEVERE, null, ex); } } } ``` 在此程序中,我們想在`Authors`表的第一行上更改作者的姓名。 我們還必須更改與該作者相關的書籍。 這是一個需要進行事務的很好的例子。 如果我們更改作者但不更改作者的書,則數據已損壞。 ```java con.setAutoCommit(false); ``` 要處理事務,我們必須將自動提交模式設置為`false`。 默認情況下,數據庫連接處于自動提交模式。 在這種模式下,每條語句在執行后都會立即提交給數據庫。 聲明無法撤消。 當自動提交關閉時,我們通過調用`commit()`提交更改,或通過調用`rollback()`方法將其回滾。 ```java st.executeUpdate("UPDATE Books SET Titl = 'Anna Karenina' " + "WHERE Id = 2"); ``` 第三個 SQL 語句有一個錯誤。 表中沒有`Titl`欄。 ```java con.commit(); ``` 如果沒有異常,則提交事務。 ```java try { con.rollback(); } catch (SQLException ex1) { Logger lgr = Logger.getLogger(JdbcTransaction.class.getName()); lgr.log(Level.WARNING, ex1.getMessage(), ex1); } ``` 發生異常時,事務將回滾。 沒有更改提交到數據庫。 ```java Feb 21, 2018 2:35:14 PM com.zetcode.JdbcTransaction main SEVERE: Unknown column 'Titl' in 'field list' com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Titl' in 'field list' ``` 該應用以異常結束。 ```java mysql> SELECT Name, Title From Authors, Books WHERE Authors.Id=Books.AuthorId; +-------------------+----------------------+ | Name | Title | +-------------------+----------------------+ | Jack London | Call of the Wild | | Jack London | Martin Eden | | Honore de Balzac | Old Goriot | | Honore de Balzac | Cousin Bette | | Lion Feuchtwanger | Jew Suess | | Emile Zola | Nana | | Emile Zola | The Belly of Paris | | Truman Capote | In Cold blood | | Truman Capote | Breakfast at Tiffany | +-------------------+----------------------+ 9 rows in set (0.01 sec) ``` 事務已回滾,并且未進行任何更改。 但是,如果沒有事務,數據是不安全的。 `JdbcNoTransaction.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcNoTransaction { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; try (Connection con = DriverManager.getConnection(url, user, password); Statement st = con.createStatement()) { st.executeUpdate("UPDATE Authors SET Name = 'Leo Tolstoy'" + "WHERE Id = 1"); st.executeUpdate("UPDATE Books SET Title = 'War and Peace'" + "WHERE Id = 1"); st.executeUpdate("UPDATE Books SET Titl = 'Anna Karenina'" + "WHERE Id = 2"); } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcNoTransaction.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 我們有同樣的例子。 這次,沒有事務支持。 ```java mysql> SELECT Name, Title From Authors, Books WHERE Authors.Id=Books.AuthorId; +-------------------+----------------------+ | Name | Title | +-------------------+----------------------+ | Leo Tolstoy | War and Peace | | Leo Tolstoy | Martin Eden | | Honore de Balzac | Old Goriot | | Honore de Balzac | Cousin Bette | | Lion Feuchtwanger | Jew Suess | | Emile Zola | Nana | | Emile Zola | The Belly of Paris | | Truman Capote | In Cold blood | | Truman Capote | Breakfast at Tiffany | +-------------------+----------------------+ 9 rows in set (0.00 sec) ``` 再次引發異常。 列夫·托爾斯泰沒有寫馬丁·伊甸園; 數據已損壞。 ## 批量更新 當我們需要使用多個語句更新數據時,可以使用批處理更新。 批處理更新可用于`INSERT`,`UPDATE`,`DELETE`語句以及`CREATE TABLE`和`DROP TABLE`語句。 `JdbcBatchUpdate.java` ```java package com.zetcode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcBatchUpdate { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; try (Connection con = DriverManager.getConnection(url, user, password)) { try (Statement st = con.createStatement()) { con.setAutoCommit(false); st.addBatch("DROP TABLE IF EXISTS Authors2"); st.addBatch("CREATE TABLE Authors2(Id INT PRIMARY KEY, " + "Name VARCHAR(100))"); st.addBatch("INSERT INTO Authors2(Id, Name) " + "VALUES(1, 'Jack London')"); st.addBatch("INSERT INTO Authors2(Id, Name) " + "VALUES(2, 'Honore de Balzac')"); st.addBatch("INSERT INTO Authors2(Id, Name) " + "VALUES(3, 'Lion Feuchtwanger')"); st.addBatch("INSERT INTO Authors2(Id, Name) " + "VALUES(4, 'Emile Zola')"); st.addBatch("INSERT INTO Authors2(Id, Name) " + "VALUES(5, 'Truman Capote')"); st.addBatch("INSERT INTO Authors2(Id, Name) " + "VALUES(6, 'Umberto Eco')"); int counts[] = st.executeBatch(); con.commit(); System.out.printf("Committed %d updates", counts.length); } catch (SQLException ex) { try { con.rollback(); } catch (SQLException ex2) { Logger lgr = Logger.getLogger(JdbcBatchUpdate.class.getName()); lgr.log(Level.FINEST, ex2.getMessage(), ex2); } Logger lgr = Logger.getLogger(JdbcBatchUpdate.class.getName()); lgr.log(Level.FINEST, ex.getMessage(), ex); } } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcBatchUpdate.class.getName()); lgr.log(Level.FINEST, ex.getMessage(), ex); } } } ``` 這是用于批處理更新的示例程序。 我們從`Authors`表中刪除所有數據,然后插入新數據。 我們添加了一位新作者,`Umberto Eco`,以查看更改。 ```java st.addBatch("DROP TABLE IF EXISTS Authors2"); st.addBatch("CREATE TABLE Authors2(Id INT PRIMARY KEY, " + "Name VARCHAR(100))"); st.addBatch("INSERT INTO Authors2(Id, Name) " + "VALUES(1, 'Jack London')"); ... ``` 我們使用`addBatch()`方法向該語句添加新命令。 ```java int counts[] = st.executeBatch(); ``` 添加所有命令后,我們調用`executeBatch()`進行批量更新。 該方法返回已提交更改的數組。 ```java con.commit(); ``` 批處理更新在事務中提交。 ```java } catch (SQLException ex) { try { con.rollback(); } catch (SQLException ex2) { Logger lgr = Logger.getLogger(JdbcBatchUpdate.class.getName()); lgr.log(Level.FINEST, ex2.getMessage(), ex2); } Logger lgr = Logger.getLogger(JdbcBatchUpdate.class.getName()); lgr.log(Level.FINEST, ex.getMessage(), ex); } ``` 萬一批量更新失敗,我們將其稱為`rollback()`。 ```java $ mvn exec:java -q Committed 8 updates mysql> SELECT * from Authors2; +----+-------------------+ | Id | Name | +----+-------------------+ | 1 | Jack London | | 2 | Honore de Balzac | | 3 | Lion Feuchtwanger | | 4 | Emile Zola | | 5 | Truman Capote | | 6 | Umberto Eco | +----+-------------------+ 6 rows in set (0.00 sec) ``` 我們執行`BatchUpdate`程序。 `SELECT`語句顯示`Authors2`表已成功更新。 它有一個新作者,Umerto Eco。 ## 將數據導出到 CSV 文件 下一個示例將數據導出到 CSV 文件。 我們需要對`testuser`具有適當的文件許可權; 否則,我們會收到拒絕訪問錯誤消息。 ```java mysql> GRANT FILE ON *.* TO 'testuser'@'localhost'; ``` 我們設置了`FILE`權限。 ```java mysql> SHOW VARIABLES LIKE "secure_file_priv"; +------------------+-----------------------+ | Variable_name | Value | +------------------+-----------------------+ | secure_file_priv | /var/lib/mysql-files/ | +------------------+-----------------------+ 1 row in set (0.26 sec) ``` 出于安全原因,MySQL 從啟用`--secure-file-priv`選項開始,該選項僅允許處理特定目錄中的文件。 該目錄在`secure_file_priv`變量中指定。 在 Windows 上,路徑類似于`'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads'`。 `ExportCSV.java` ```java package com.zetcode; import java.sql.PreparedStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; public class JdbcExportCSV { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false"; String user = "testuser"; String password = "test623"; String query = "SELECT Name, Title INTO OUTFILE " + "'/var/lib/mysql-files/authors_books.csv' " + "FIELDS TERMINATED BY ',' " + "FROM Authors, Books WHERE " + "Authors.Id=Books.AuthorId"; try (Connection con = DriverManager.getConnection(url, user, password); PreparedStatement pst = con.prepareStatement(query)) { pst.execute(); } catch (SQLException ex) { Logger lgr = Logger.getLogger(JdbcExportCSV.class.getName()); lgr.log(Level.SEVERE, ex.getMessage(), ex); } } } ``` 我們將作者及其相應的書籍導出到`/var/lib/mysql-files/authors_books.csv`文件中。 ```java String query = "SELECT Name, Title INTO OUTFILE " + "'/var/lib/mysql-files/authors_books.csv' " + "FIELDS TERMINATED BY ',' " + "FROM Authors, Books WHERE " + "Authors.Id=Books.AuthorId"; ``` 要將數據導出到文件中,我們使用`SELECT INTO OUTFILE` SQL 語句。 ```java $ cat /var/lib/mysql-files/authors_books.csv Jack London,Call of the Wild Jack London,Martin Eden Honore de Balzac,Old Goriot Honore de Balzac,Cousin Bette Lion Feuchtwanger,Jew Suess Emile Zola,Nana Emile Zola,The Belly of Paris Truman Capote,In Cold blood Truman Capote,Breakfast at Tiffany ``` 我們驗證數據。 這是 MySQL Java 教程。 您可能也對 [JDBI 教程](/db/jdbi/), [Java H2 教程](/java/h2database/), [PostgreSQL Java 教程](/db/postgresqljavatutorial/), [MongoDB Java 教程](/db/mongodbjava/)或 [MySQL 教程](/databases/mysqltutorial/)感興趣。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看