引言
在当今的软件开发中,数据库与应用程序之间的交互至关重要。Java作为一种广泛使用的编程语言,提供了多种方式来与数据库建立联系。其中,JDBC(Java Database Connectivity)和MyBatis是两种常用的技术。为了更好地了解Java与数据库之间建立联系的过程,本文将对JDBC与MyBatis进行对比分析。
JDBC介绍
JDBC(Java Database Connectivity)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问。它由一组用Java语言编写的类和接口组成,是Java访问数据库的标准规范。
jdbc的主要类和接口:
- Connection:
Connection
接口代表与特定数据库的连接,可以执行SQL语句并返回结果。通常,首先需要创建一个Connection
对象来建立与数据库的连接。 - Statement:
Statement
接口用于执行静态SQL语句并返回结果。它可以通过Connection
对象创建,并用于执行查询和更新操作。 - PreparedStatement:
PreparedStatement
接口扩展了Statement
接口,并允许执行参数化SQL语句。它提供了设置参数的方法,可以用于执行带有参数的查询和更新。 - CallableStatement:
CallableStatement
接口扩展了PreparedStatement
接口,并允许执行存储过程。它提供了设置输入参数和获取输出参数的方法。 - ResultSet:
ResultSet
接口表示查询操作返回的结果集。通过ResultSet
对象,可以检索查询结果中的数据,包括获取列值、列名等。 - DriverManager:
DriverManager
类是JDBC API中的核心类,用于管理数据库驱动程序。它提供了用于获取与特定数据库的连接的方法,如getConnection()
。 - SQLException:
SQLException
是JDBC API中用于表示异常的类。在执行SQL语句或与数据库交互时,可能会抛出此异常。
jdbc接口方法具体介绍可参考此博客http://t.csdnimg.cn/W3wqG
jdbc的操作数据库的流程
- 加载数据库驱动:首先需要加载数据库的JDBC驱动,可以使用Class.forName()方法来加载。
Class.forName("com.mysql.jdbc.Driver");
- 创建数据库连接:使用DriverManager.getConnection()方法来建立与数据库的连接,需要提供数据库的URL、用户名和密码。
Connection connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username",
"password");
- 创建Statement对象:使用Connection对象创建Statement对象,用于执行SQL语句。
Statement statement = connection.createStatement();
- 执行SQL语句:使用Statement对象的executeQuery()或executeUpdate()方法来执行SQL语句。
ResultSet resultSet = statement.executeQuery("SELECT * FROM user");
- 处理结果集:对于查询语句,executeQuery()方法返回一个ResultSet对象,可以从中获取查询结果。
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
// ...
}
- 关闭连接和释放资源:使用Connection对象的close()方法关闭连接,并释放相关资源。
connection.close();
jdbc操作数据库具体案例:
用户数据库表:
POJO类
@Data
public class User {
private Integer userId;
private String userName;
private String password;
}
DAO(数据访问对象)
public class UserDAO {
private static final String URL = "jdbc:mysql://localhost:3306/crud?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "root";
public User getUserById(int userId) {
User user=null;
String query = "SELECT * FROM user WHERE user_id = ?";
try {
// 加载MySQL数据库驱动
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace(); // 处理异常
}
try (
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
PreparedStatement statement = connection.prepareStatement(query)) {
// 设置查询参数
statement.setInt(1, userId);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
user = new User();
user.setUserId(resultSet.getInt("user_id")) ;
user.setUserName(resultSet.getString("user_name"));
user.setPassword(resultSet.getString("password"));
}
}
} catch (SQLException e) {
// 处理异常
e.printStackTrace();
}
// 返回用户对象
return user;
}
}
主函数运行代码:
public class Main {
public static void main(String[] args) {
//创建dao对象实例
UserDAO userDAO=new UserDAO();
//调用通过id查询对象的方法
User userById = userDAO.getUserById(1);
//输出获取结果
System.out.println(userById);
}
}
运行结果:
Mybatis介绍
MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis消除了几乎所有的JDBC代码和参数的手动设置以及结果集的检索。MyBatis可以使用简单的XML或注解来配置和映射原生信息,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
Mybatis执行流程
- 加载配置文件:MyBatis在启动时,会加载配置文件,包括
mybatis-config.xml
和映射文件(.xml
文件)。 - 创建SqlSessionFactory:基于MyBatis的配置信息,创建一个SqlSessionFactory实例。SqlSessionFactory是线程安全的,可以被多个线程共享。
- 创建SqlSession:通过SqlSessionFactory实例,可以创建SqlSession。SqlSession是非线程安全的,应该避免在多个线程中共享SqlSession实例。每个线程都应该拥有自己的SqlSession实例。
- Mapper调用:在SqlSession中,可以通过Mapper接口调用相应的方法,执行SQL语句。
- 结果映射:SQL执行的结果会被映射到Java对象中。如果SQL查询返回多行结果,MyBatis会将这些结果映射到一个List中。如果查询返回单行结果,MyBatis会直接映射到对应的Java对象。
- 关闭SqlSession:当SqlSession实例不再需要时,应该关闭它以释放资源。关闭SqlSession后,不能再使用该实例。
mybatis操作数据库具体案例:
基于上面jdbc使用的用户表以及实体类操作
业务接口以及实现类:
public interface UserService {
//查询所有用户
List<User> selectAll();
}
public class UserServiceImpl implements UserService {
@Override
public List<User> selectAll() {
InputStream inputStream=null;
List<User> userList=null;
try {
//读取配置文件
inputStream= Resources.getResourceAsStream("mybatis/mybatis-config.xml");
//基于构建者模式创建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//基于工厂模式创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//基于代理模式创建代理对象实例
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
userList=mapper.selectAll();
} catch (IOException e) {
throw new RuntimeException(e);
}
return userList;
}
数据访问接口:
public interface UserMapper {
List<User> selectAll();
}
mybatis全局映射文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 环境配置 default的值与下面environment的id值相同则使用那个环境-->
<properties resource="props/db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<environment id="runtime">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mybatis/mappers/UserMapper.xml"/>
</mappers>
</configuration>
注意:一定不要忘记在全局配置文件中加载连接数据库文件的配置信息
<properties resource="props/db.properties"></properties>
否则运行时会报一下错误
### Error querying database. Cause: java.sql.SQLException: Error setting driver on UnpooledDataSource. Cause: java.lang.ClassNotFoundException: Cannot find class: ${jdbc.driverClass}
数据库文件配置:
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/crud?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC
jdbc.username=root
jdbc.password=root
映射文件代码:
<?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.yaorange.mapper.UserMapper">
<resultMap id="BaseResult" type="com.yaorange.domain.User">
<id column="user_id" property="userId"></id>
<result column="user_name" property="userName"></result>
<result column="password" property="password"></result>
</resultMap>
<sql id="BaseField">
user.user_id, user.user_name, user.password
</sql>
<select id="selectAll" resultMap="BaseResult">
SELECT
<include refid="BaseField"/>
FROM
user
</select>
</mapper>
ps:(上面的业务层代码依然十分冗余,其实应该把对sqlsession对象的那部分代码抽象成一个工具类,但由于我只是展示mybatis的执行流程所以仅仅演示代码执行过程,并没有做相应的优化.)
mybatis配置介绍:
MyBatis 的配置文件通常是一个 XML 文件,用于配置 MyBatis 的运行时环境。这个文件通常命名为
mybatis-config.xml
。
配置数据源:
在 mybatis-config.xml
中,需要配置数据源。数据源是用于连接数据库的,一下代码用于动态配置数据源
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
引入外部属性文件,配置数据库连接信息
<properties resource="props/db.properties"></properties>
配置映射文件:
<mappers>
<mapper resource="mybatis/mappers/UserMapper.xml"/>
</mappers>
原生JDBC与Mybatis的对比:
Mybatis与原生JDBC相比主要有以下改变:
连接管理:
- 使用JDBC时,每次操作数据库都需要手动建立数据库连接,并在操作完成后关闭连接。这会导致大量的资源浪费和潜在的连接泄漏问题。
- MyBatis 提供了统一的连接管理,减少了代码中与数据库连接相关的工作量。
SQL 语句编写
- 使用JDBC时,开发者需要直接编写SQL语句,并在代码中拼接参数。这可能导致 SQL 注入的风险。
- MyBatis 允许将 SQL 语句与参数分开定义,降低了 SQL 注入的风险。
结果集处理
- 使用JDBC时,开发者需要手动将结果集转换为 Java 对象。
- MyBatis 可以自动将结果集映射到 Java 对象,简化了结果集的处理过程。
事务管理:
- 使用JDBC时,事务管理需要手动控制,包括开始事务、提交事务和回滚事务等操作。
- MyBatis 提供了声明式事务管理,开发者只需关注业务逻辑,而无需关心事务的具体操作。
缓存机制:
- MyBatis 提供了两级缓存机制,包括本地缓存和全局缓存,提高了查询效率。
简化复杂查询:
- 对于复杂的查询和存储过程,使用原生JDBC可能会变得非常复杂和混乱。MyBatis通过映射文件简化了这些复杂查询的编写和管理。
类型转换和结果映射:
- MyBatis 内置了强大的类型转换和结果映射机制,可以方便地处理各种数据类型和结果集的映射问题。
小结
原生JDBC与MyBatis相比,MyBatis在连接管理、SQL语句编写、结果集处理、事务管理、缓存机制、映射文件配置等方面简化了流程。MyBatis提供了统一的连接管理、降低了SQL注入风险、自动映射结果集、声明式事务管理,并提供了丰富的扩展点和集成能力。相比之下,原生JDBC需要手动处理这些繁琐的任务,容易导致资源浪费和安全风险。