JDBC 與 MyBatis從基礎(chǔ)到實(shí)踐
一、JDBC 介紹
JDBC(Java Database Connectivity)即 Java 數(shù)據(jù)庫(kù)連接,是 Java 語(yǔ)言中用來(lái)規(guī)范客戶端程序如何來(lái)訪問(wèn)數(shù)據(jù)庫(kù)的應(yīng)用程序接口,提供了諸如查詢和更新數(shù)據(jù)庫(kù)中數(shù)據(jù)的方法。它由一組用 Java 語(yǔ)言編寫的類和接口組成,使得 Java 程序能夠與各種關(guān)系型數(shù)據(jù)庫(kù)進(jìn)行交互,如 MySQL、Oracle、SQL Server 等。通過(guò) JDBC,開發(fā)人員可以在 Java 代碼中執(zhí)行 SQL 語(yǔ)句,處理數(shù)據(jù)庫(kù)事務(wù),獲取查詢結(jié)果等。
二、使用 JDBC 查詢用戶信息
下面是一個(gè)簡(jiǎn)單的使用 JDBC 查詢用戶信息的示例代碼:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class JDBCUserQuery { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/mydb"; String user = "root"; String password = "password"; try (Connection connection = DriverManager.getConnection(url, user, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT * FROM users")) { while (resultSet.next()) { int id = resultSet.getInt("id"); String username = resultSet.getString("username"); String email = resultSet.getString("email"); System.out.println("ID: " + id + ", Username: " + username + ", Email: " + email); } } catch (SQLException e) { e.printStackTrace(); } } }
在上述代碼中,首先通過(guò)
DriverManager.getConnection()
方法獲取數(shù)據(jù)庫(kù)連接,然后創(chuàng)建Statement
對(duì)象用于執(zhí)行 SQL 語(yǔ)句,最后執(zhí)行executeQuery()
方法獲取ResultSet
結(jié)果集,并遍歷結(jié)果集輸出用戶信息。
三、ResultSet 結(jié)果集
ResultSet
是 JDBC 中用于存儲(chǔ)數(shù)據(jù)庫(kù)查詢結(jié)果的對(duì)象。它就像一個(gè)表格,每一行代表一條記錄,每一列代表一個(gè)字段。ResultSet
提供了一系列方法來(lái)訪問(wèn)其中的數(shù)據(jù),如getInt()
、getString()
、getDouble()
等,根據(jù)字段的數(shù)據(jù)類型來(lái)獲取相應(yīng)的值。同時(shí),ResultSet
有一個(gè)游標(biāo),默認(rèn)位于第一行之前,通過(guò)next()
方法可以將游標(biāo)移動(dòng)到下一行,當(dāng)游標(biāo)指向有效行時(shí),才能獲取該行的數(shù)據(jù)。當(dāng)游標(biāo)移動(dòng)到結(jié)果集的末尾(即next()
方法返回false
)時(shí),表示結(jié)果集遍歷結(jié)束。
四、預(yù)編譯 SQL - SQL 注入問(wèn)題
SQL 注入是一種常見的安全漏洞,攻擊者通過(guò)在輸入?yún)?shù)中插入惡意的 SQL 代碼,從而改變?cè)?SQL 語(yǔ)句的邏輯,獲取敏感信息或進(jìn)行非法操作。例如,在一個(gè)用戶登錄驗(yàn)證的場(chǎng)景中,如果使用普通的 SQL 語(yǔ)句拼接用戶輸入:
String username = request.getParameter("username"); String password = request.getParameter("password"); String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
如果用戶輸入的
username
為' OR '1'='1
,那么拼接后的 SQL 語(yǔ)句就變成了SELECT * FROM users WHERE username = '' OR '1'='1' AND password = ''
,這樣無(wú)論密碼是否正確,都能成功登錄。預(yù)編譯 SQL 可以有效防止 SQL 注入問(wèn)題。預(yù)編譯 SQL 是將 SQL 語(yǔ)句先發(fā)送到數(shù)據(jù)庫(kù)進(jìn)行編譯,然后再將參數(shù)傳遞給已經(jīng)編譯好的語(yǔ)句。在 JDBC 中,使用
PreparedStatement
來(lái)實(shí)現(xiàn)預(yù)編譯 SQL:
String url = "jdbc:mysql://localhost:3306/mydb"; String user = "root"; String password = "password"; String username = request.getParameter("username"); String password = request.getParameter("password"); try (Connection connection = DriverManager.getConnection(url, user, password); PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM users WHERE username =? AND password =?")) { preparedStatement.setString(1, username); preparedStatement.setString(2, password); ResultSet resultSet = preparedStatement.executeQuery(); // 處理結(jié)果集 } catch (SQLException e) { e.printStackTrace(); }
在上述代碼中,使用
?
作為占位符,然后通過(guò)setString()
等方法設(shè)置參數(shù),這樣數(shù)據(jù)庫(kù)會(huì)將參數(shù)作為普通值處理,而不會(huì)將其解析為 SQL 代碼,從而避免了 SQL 注入問(wèn)題。
五、預(yù)編譯 SQL - 性能更高
預(yù)編譯 SQL 除了能防止 SQL 注入外,還具有更高的性能。當(dāng)使用普通的
Statement
執(zhí)行 SQL 語(yǔ)句時(shí),數(shù)據(jù)庫(kù)每次都需要對(duì) SQL 語(yǔ)句進(jìn)行語(yǔ)法解析、查詢優(yōu)化等操作。而預(yù)編譯 SQL 會(huì)將 SQL 語(yǔ)句先編譯好,后續(xù)如果執(zhí)行相同結(jié)構(gòu)的 SQL 語(yǔ)句,只需要傳遞參數(shù)即可,數(shù)據(jù)庫(kù)不需要再次進(jìn)行語(yǔ)法解析和查詢優(yōu)化,從而提高了執(zhí)行效率。特別是在需要頻繁執(zhí)行相同結(jié)構(gòu) SQL 語(yǔ)句的場(chǎng)景下,預(yù)編譯 SQL 的性能優(yōu)勢(shì)更加明顯。
六、JDBC 增刪改操作
以下是使用 JDBC 進(jìn)行增刪改操作的示例代碼:
插入數(shù)據(jù):
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class JDBCInsert { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/mydb"; String user = "root"; String password = "password"; try (Connection connection = DriverManager.getConnection(url, user, password); PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO users (username, email, password) VALUES (?,?,?)")) { preparedStatement.setString(1, "newuser"); preparedStatement.setString(2, "newuser@example.com"); preparedStatement.setString(3, "newpassword"); int rowsInserted = preparedStatement.executeUpdate(); if (rowsInserted > 0) { System.out.println("A new user was inserted successfully!"); } } catch (SQLException e) { e.printStackTrace(); } } }
更新數(shù)據(jù):
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class JDBCUpdate { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/mydb"; String user = "root"; String password = "password"; try (Connection connection = DriverManager.getConnection(url, user, password); PreparedStatement preparedStatement = connection.prepareStatement("UPDATE users SET password =? WHERE username =?")) { preparedStatement.setString(1, "newpassword123"); preparedStatement.setString(2, "newuser"); int rowsUpdated = preparedStatement.executeUpdate(); if (rowsUpdated > 0) { System.out.println("User password was updated successfully!"); } } catch (SQLException e) { e.printStackTrace(); } } }
刪除數(shù)據(jù):
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class JDBCDelete { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/mydb"; String user = "root"; String password = "password"; try (Connection connection = DriverManager.getConnection(url, user, password); PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM users WHERE username =?")) { preparedStatement.setString(1, "newuser"); int rowsDeleted = preparedStatement.executeUpdate(); if (rowsDeleted > 0) { System.out.println("User was deleted successfully!"); } } catch (SQLException e) { e.printStackTrace(); } } }
七、MyBatis 介紹
MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集,它可以使用簡(jiǎn)單的 XML 或注解來(lái)配置和映射原生信息,將接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 對(duì)象)映射成數(shù)據(jù)庫(kù)中的記錄。MyBatis 對(duì) JDBC 進(jìn)行了封裝,使得數(shù)據(jù)庫(kù)操作更加簡(jiǎn)潔、高效,同時(shí)也提高了代碼的可維護(hù)性和可擴(kuò)展性。
八、MyBatis 入門程序
以下是一個(gè)簡(jiǎn)單的 MyBatis 入門示例:
引入依賴:
在 Maven 項(xiàng)目的
pom.xml
文件中添加 MyBatis 和數(shù)據(jù)庫(kù)驅(qū)動(dòng)依賴:
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> </dependencies>
創(chuàng)建實(shí)體類:
public class User { private int id; private String username; private String email; private String password; // 省略 getters 和 setters }
創(chuàng)建 SQL 映射文件(UserMapper.xml):
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.UserMapper"> <select id="getUserById" parameterType="int" resultType="com.example.User"> SELECT * FROM users WHERE id = #{id} </select> </mapper>
配置 MyBatis 核心文件(mybatis-config.xml):
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb"/> <property name="username" value="root"/> <property name="password" value="password"/> </dataSource> </environment> </environments> <mappers> <mapper resource="UserMapper.xml"/> </mappers> </configuration>
編寫測(cè)試代碼:
import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class MyBatisTest { public static void main(String[] args) throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession sqlSession = sqlSessionFactory.openSession()) { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.getUserById(1); System.out.println(user.getUsername()); } } }
九、MyBatis 輔助配置 - SQL 提示
為了在開發(fā)過(guò)程中獲得更好的 SQL 提示,可以使用一些 IDE 插件,如在 IntelliJ IDEA 中安裝 MyBatis Log Plugin 等插件,這些插件可以將 MyBatis 執(zhí)行的 SQL 語(yǔ)句打印出來(lái),并對(duì) SQL 語(yǔ)法進(jìn)行高亮顯示和提示,方便開發(fā)人員調(diào)試和優(yōu)化 SQL 語(yǔ)句。同時(shí),也可以在 SQL 映射文件中使用
<!-- -->
進(jìn)行注釋,對(duì) SQL 語(yǔ)句的功能和邏輯進(jìn)行說(shuō)明,提高代碼的可讀性。
十、MyBatis 輔助配置 - 日志輸出
MyBatis 支持配置日志輸出,以便更好地了解程序的執(zhí)行情況。可以通過(guò)在
mybatis-config.xml
文件中配置日志工廠來(lái)實(shí)現(xiàn)。例如,使用 Log4j 作為日志框架:
引入 Log4j 依賴:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.14.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.1</version> </dependency>
配置 Log4j 配置文件(log4j2.xml)
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> <Loggers> <Root level="error"> <AppenderRef ref="Console"/> </Root> <Logger name="com.example" level="debug"/> </Loggers> </Configuration>
在 MyBatis 配置文件中啟用日志:
<configuration> <settings> <setting name="logImpl" value="LOG4J2"/> </settings> <!-- 其他配置 --> </configuration>
這樣,MyBatis 執(zhí)行的 SQL 語(yǔ)句等信息就會(huì)按照配置的日志級(jí)別進(jìn)行輸出。
十一、MyBatis 數(shù)據(jù)庫(kù)連接池
MyBatis 支持使用不同的數(shù)據(jù)庫(kù)連接池,如
POOLED
連接池(默認(rèn))、UNPOOLED
連接池等。POOLED
連接池會(huì)管理一定數(shù)量的數(shù)據(jù)庫(kù)連接,當(dāng)需要連接時(shí)從連接池中獲取,使用完畢后再歸還到連接池,這樣可以避免頻繁地創(chuàng)建和銷毀數(shù)據(jù)庫(kù)連接,提高性能。在mybatis-config.xml
文件中配置POOLED
連接池的示例如下:
<environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb"/> <property name="username" value="root"/> <property name="password" value="password"/> </dataSource> </environment>
此外,也可以使用第三方連接池,如 HikariCP、C3P0 等,只需要在項(xiàng)目中引入相應(yīng)的依賴,并在 MyBatis 配置文件中進(jìn)行相應(yīng)的配置即可。
十二、MyBatis 增刪改查 - 刪除用戶
以下是使用 MyBatis 實(shí)現(xiàn)刪除用戶的示例:
在 SQL 映射文件(UserMapper.xml)中添加刪除語(yǔ)句:
<mapper namespace="com.example.UserMapper"> <!-- 其他語(yǔ)句 --> <delete id="deleteUserById" parameterType="int"> DELETE FROM users WHERE id = #{id} </delete> </mapper>
在接口(UserMapper.java)中添加對(duì)應(yīng)的方法:
public interface UserMapper { // 其他方法 int deleteUserById(int id); }
編寫測(cè)試代碼:
import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class MyBatisDeleteTest { public static void main(String[] args) throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession sqlSession = sqlSessionFactory.openSession()) { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); int rowsDeleted = userMapper.deleteUserById(1); if (rowsDeleted > 0) { System.out.println("User was deleted successfully!"); } sqlSession.commit(); } } }
在上述代碼中,通過(guò)
UserMapper
接口的deleteUserById()
方法執(zhí)行刪除操作,最后調(diào)用sqlSession.commit()
方法提交事務(wù)。通過(guò)以上對(duì) JDBC 和 MyBatis 的詳細(xì)介紹和示例代碼,希望能幫助讀者更好地理解和掌握這兩種數(shù)據(jù)庫(kù)操作技術(shù),在實(shí)際項(xiàng)目中選擇合適的方式進(jìn)行數(shù)據(jù)庫(kù)開發(fā)。
到此這篇關(guān)于JDBC 與 MyBatis從基礎(chǔ)到實(shí)踐的文章就介紹到這了,更多相關(guān)JDBC 與 MyBatis詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatis 如何簡(jiǎn)化的 JDBC(思路詳解)
- 詳解如何使用MyBatis簡(jiǎn)化JDBC開發(fā)
- MyBatis中的JdbcType映射使用詳解
- sharding-jdbc 兼容 MybatisPlus動(dòng)態(tài)數(shù)據(jù)源的配置方法
- MySQL text類型對(duì)應(yīng)mybatis jdbcType類型方式
- 解決mybatis plus報(bào)錯(cuò)com.microsoft.sqlserver.jdbc.SQLServerException:必須執(zhí)行該語(yǔ)句才能獲得結(jié)果
- 淺談MyBatis所有的jdbcType類型
- SpringBoot多數(shù)據(jù)源配置詳細(xì)教程(JdbcTemplate、mybatis)
相關(guān)文章
淺談MultipartFile中transferTo方法的坑
這篇文章主要介紹了MultipartFile中transferTo方法的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07springboot-curd基于mybatis項(xiàng)目搭建
這篇文章主要介紹了springboot-curd基于mybatis項(xiàng)目搭建,圍繞相關(guān)資料展開詳細(xì)內(nèi)容,希望對(duì)正在學(xué)習(xí)的你有所幫助,需要的小伙伴也可以參考一下2022-01-01Mybatis開發(fā)要點(diǎn)-resultType和resultMap有什么區(qū)別詳解
本文主要介紹了Mybatis開發(fā)要點(diǎn)-resultType和resultMap有什么區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04java通過(guò)反射創(chuàng)建對(duì)象并調(diào)用方法
這篇文章主要介紹了java通過(guò)反射創(chuàng)建對(duì)象并調(diào)用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01java實(shí)現(xiàn)動(dòng)態(tài)圖片效果
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)動(dòng)態(tài)圖片效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03Java實(shí)現(xiàn)數(shù)組去除重復(fù)數(shù)據(jù)的方法詳解
這篇文章主要介紹了Java實(shí)現(xiàn)數(shù)組去除重復(fù)數(shù)據(jù)的方法,結(jié)合實(shí)例形式詳細(xì)分析了java數(shù)組去除重復(fù)的幾種常用方法、實(shí)現(xiàn)原理與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-09-09