JDBC 与 MyBatis 详解:从基础到实践
目录
一、JDBC 介绍
二、使用 JDBC 查询用户信息
三、ResultSet 结果集
四、预编译 SQL - SQL 注入问题
五、预编译 SQL - 性能更高
六、JDBC 增删改操作
插入数据:
更新数据:
删除数据:
七、MyBatis 介绍
八、MyBatis 入门程序
引入依赖:
创建实体类:
创建 SQL 映射文件(UserMapper.xml):
配置 MyBatis 核心文件(mybatis-config.xml):
编写测试代码:
九、MyBatis 辅助配置 - SQL 提示
十、MyBatis 辅助配置 - 日志输出
引入 Log4j 依赖:
配置 Log4j 配置文件(log4j2.xml)
在 MyBatis 配置文件中启用日志:
十一、MyBatis 数据库连接池
十二、MyBatis 增删改查 - 删除用户
在 SQL 映射文件(UserMapper.xml)中添加删除语句:
在接口(UserMapper.java)中添加对应的方法:
编写测试代码:
一、JDBC 介绍
JDBC(Java Database Connectivity)即 Java 数据库连接,是 Java 语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。它由一组用 Java 语言编写的类和接口组成,使得 Java 程序能够与各种关系型数据库进行交互,如 MySQL、Oracle、SQL Server 等。通过 JDBC,开发人员可以在 Java 代码中执行 SQL 语句,处理数据库事务,获取查询结果等。
二、使用 JDBC 查询用户信息
下面是一个简单的使用 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();}}
}
在上述代码中,首先通过
DriverManager.getConnection()
方法获取数据库连接,然后创建Statement
对象用于执行 SQL 语句,最后执行executeQuery()
方法获取ResultSet
结果集,并遍历结果集输出用户信息。
三、ResultSet 结果集
ResultSet
是 JDBC 中用于存储数据库查询结果的对象。它就像一个表格,每一行代表一条记录,每一列代表一个字段。ResultSet
提供了一系列方法来访问其中的数据,如getInt()
、getString()
、getDouble()
等,根据字段的数据类型来获取相应的值。同时,ResultSet
有一个游标,默认位于第一行之前,通过next()
方法可以将游标移动到下一行,当游标指向有效行时,才能获取该行的数据。当游标移动到结果集的末尾(即next()
方法返回false
)时,表示结果集遍历结束。
四、预编译 SQL - SQL 注入问题
SQL 注入是一种常见的安全漏洞,攻击者通过在输入参数中插入恶意的 SQL 代码,从而改变原本 SQL 语句的逻辑,获取敏感信息或进行非法操作。例如,在一个用户登录验证的场景中,如果使用普通的 SQL 语句拼接用户输入:
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 语句就变成了SELECT * FROM users WHERE username = '' OR '1'='1' AND password = ''
,这样无论密码是否正确,都能成功登录。预编译 SQL 可以有效防止 SQL 注入问题。预编译 SQL 是将 SQL 语句先发送到数据库进行编译,然后再将参数传递给已经编译好的语句。在 JDBC 中,使用
PreparedStatement
来实现预编译 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();// 处理结果集
} catch (SQLException e) {e.printStackTrace();
}
在上述代码中,使用
?
作为占位符,然后通过setString()
等方法设置参数,这样数据库会将参数作为普通值处理,而不会将其解析为 SQL 代码,从而避免了 SQL 注入问题。
五、预编译 SQL - 性能更高
预编译 SQL 除了能防止 SQL 注入外,还具有更高的性能。当使用普通的
Statement
执行 SQL 语句时,数据库每次都需要对 SQL 语句进行语法解析、查询优化等操作。而预编译 SQL 会将 SQL 语句先编译好,后续如果执行相同结构的 SQL 语句,只需要传递参数即可,数据库不需要再次进行语法解析和查询优化,从而提高了执行效率。特别是在需要频繁执行相同结构 SQL 语句的场景下,预编译 SQL 的性能优势更加明显。
六、JDBC 增删改操作
以下是使用 JDBC 进行增删改操作的示例代码:
插入数据:
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();}}
}
更新数据:
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();}}
}
删除数据:
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 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集,它可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。MyBatis 对 JDBC 进行了封装,使得数据库操作更加简洁、高效,同时也提高了代码的可维护性和可扩展性。
八、MyBatis 入门程序
以下是一个简单的 MyBatis 入门示例:
引入依赖:
在 Maven 项目的
pom.xml
文件中添加 MyBatis 和数据库驱动依赖:
<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>
创建实体类:
public class User {private int id;private String username;private String email;private String password;// 省略 getters 和 setters
}
创建 SQL 映射文件(UserMapper.xml):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//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 configurationPUBLIC "-//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>
编写测试代码:
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 提示
为了在开发过程中获得更好的 SQL 提示,可以使用一些 IDE 插件,如在 IntelliJ IDEA 中安装 MyBatis Log Plugin 等插件,这些插件可以将 MyBatis 执行的 SQL 语句打印出来,并对 SQL 语法进行高亮显示和提示,方便开发人员调试和优化 SQL 语句。同时,也可以在 SQL 映射文件中使用
<!-- -->
进行注释,对 SQL 语句的功能和逻辑进行说明,提高代码的可读性。
十、MyBatis 辅助配置 - 日志输出
MyBatis 支持配置日志输出,以便更好地了解程序的执行情况。可以通过在
mybatis-config.xml
文件中配置日志工厂来实现。例如,使用 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 执行的 SQL 语句等信息就会按照配置的日志级别进行输出。
十一、MyBatis 数据库连接池
MyBatis 支持使用不同的数据库连接池,如
POOLED
连接池(默认)、UNPOOLED
连接池等。POOLED
连接池会管理一定数量的数据库连接,当需要连接时从连接池中获取,使用完毕后再归还到连接池,这样可以避免频繁地创建和销毁数据库连接,提高性能。在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 等,只需要在项目中引入相应的依赖,并在 MyBatis 配置文件中进行相应的配置即可。
十二、MyBatis 增删改查 - 删除用户
以下是使用 MyBatis 实现删除用户的示例:
在 SQL 映射文件(UserMapper.xml)中添加删除语句:
<mapper namespace="com.example.UserMapper"><!-- 其他语句 --><delete id="deleteUserById" parameterType="int">DELETE FROM users WHERE id = #{id}</delete>
</mapper>
在接口(UserMapper.java)中添加对应的方法:
public interface UserMapper {// 其他方法int deleteUserById(int id);
}
编写测试代码:
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();}}
}
在上述代码中,通过
UserMapper
接口的deleteUserById()
方法执行删除操作,最后调用sqlSession.commit()
方法提交事务。通过以上对 JDBC 和 MyBatis 的详细介绍和示例代码,希望能帮助读者更好地理解和掌握这两种数据库操作技术,在实际项目中选择合适的方式进行数据库开发。