前言
原生的JDBC:
- 原生的JDBC操作数据库,书写较为繁琐,降低开发效率。
- JDBC的局限性(如代码冗余、SQL语句与Java代码紧密耦合、难以维护等)。
相比于JDBC,Mybatis的优势:
- SQL与Java代码的分离、强大的映射能力、易于维护和扩展等。
什么是Mybatis?
MyBatis是一个用于简化数据库操作、提高开发效率的持久层框架,它允许开发者通过简单的配置和映射来直接操作数据库,而无需深入处理JDBC的繁琐细节。
简而言之,Mybatis底层是基于JDBC进行的高级别封装,在简化原生JDBC操作的基础上,提高开发效率
重构用户的CRUD项目
使用Mybatis框架重构项目,可以提高项目的扩展性,为后续框架整合打下基础,这里我会介绍如何使用mybatis框架代替原生JDBC操作数据库的相关操作。
原来项目可以参考我的博客: 实战指南:深度剖析Servlet+JSP+JDBC技术栈下的用户CRUD操作-CSDN博客
这里我主要介绍DAO层的开发
重构步骤如下:
第一步:导入mybatis相关的依赖,和log4j依赖
pom.xml:
新增如下依赖
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
注意:添加log4j依赖的目的是为了在mybatis开发过程中查看sql的执行情况,以便快速定位sql的错误位置。并且添加了log4j依赖,需要导入相关的配置文件到resources
log4j.properties
### set log levels ###
log4j.rootLogger = debug,stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d %p [%c] - %m%n
log4j.logger.com.ibatis=debug
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug
log4j.logger.java.sql.Connection=debug
log4j.logger.java.sql.Statement=debug
log4j.logger.java.sql.PreparedStatement=debug,stdout
第二步:在resources目录下创建mybatis.xml文件作为mybatis的主配置文件
mybatis.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/csx_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
注意:这里的数据库名以及username和password的value值应当是自己本地mysql服务器上的数据
第三步:创建DAO层,书写与之对应的mapper.xml映射文件
UserDao:
接口和接口方法和重构之前保持差不多,目的都是定义一个实现需求的规范,无论使用JDBC还是mybatis,本质上都是对接口声明的实现。
(下面展示的接口和原本项目的接口有些不同,因为我使用mybatis时,为了保证映射关系的正确配置,将传递多个参数的情况全部封装成对象,并通过对应的对象作为参数传递)
package dao;
import entity.User;
import entity.dto.UserDto;
import entity.dto.UserDtoNew;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserDao {
/**
* 查看用户总条数
* @return
*/
int selectUsersCount();
/**
* 分页查询用户列表
* @return
*/
List<User> selectUserListByPage(UserDto userDto);
/**
* 新增用户
* @param user
* @return
*/
public int insertUser(User user);
/**
* 根据id查询指定用户信息
* @param userId
* @return
*/
public User selectUserByUserId(int userId);
/**
* 根据id删除用户信息
* @param userId
* @return
*/
public int deleteUserByUserId(int userId);
/**
* 修改用户数据
* @param user
* @return
*/
public int updateUser(User user);
/**
* 根据用户名和密码查看指定用户是否存在
* @return
*/
public User selectUserByuserNameAndpassword(UserDtoNew userDtoNew);
}
新增实体类:
UserDto:
package entity.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class UserDto implements Serializable {
private String keyword;
private Integer pageIndex;
private Integer pageSize;
}
UserDtoNew:
package entity.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Setter
public class UserDtoNew implements Serializable {
private String userName;
private String password;
}
新增实体类的目的是当DAO接口中方法的形参为多个时,将形参封装成对象进行传参,从而可以方便的进行Java的属性和数据库中的字段(列)进行映射。
mapper.xml:
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为映射的根节点,用来管理DAO接口
namespace指定DAO接口的完整类名,表示mapper配置文件管理哪个DAO接口(包.接口名)
mybatis会依据这个接口动态创建一个实现类去实现这个接口,而这个实现类是一个Mapper对象
-->
<mapper namespace="dao.UserDao">
<resultMap id="userMap" type="entity.User">
<id property="userId" column="user_id"/>
<result property="userName" column="user_name"/>
<result property="userPic" column="user_pic"/>
</resultMap>
<insert id="insertUser">
insert into t_user (user_name,password,user_pic) values (#{userName},#{password},#{userPic})
</insert>
<update id="updateUser">
update t_user set user_name=#{userName},password=#{password},user_pic=#{userPic} where user_id=#{userId}
</update>
<delete id="deleteUserByUserId">
delete from t_user where user_id=#{userId}
</delete>
<select id="selectUsersCount" resultType="java.lang.Integer">
select count(user_id) from t_user
</select>
<select id="selectUserListByPage" resultMap="userMap" parameterType="entity.dto.UserDto">
select * from t_user where user_name like concat('%',#{keyword},'%') order by user_id desc limit #{pageIndex},#{pageSize}
</select>
<select id="selectUserByUserId" resultMap="userMap">
select * from t_user where user_id = #{userId}
</select>
<select id="selectUserByuserNameAndpassword" resultMap="userMap">
select * from t_user where user_name=#{userName} and password=#{password}
</select>
<!--
id = "接口中的方法名"
parameterType = "接口中传入方法的参数类型"
resultType = "返回实体类对象:包.类名" 处理结果集 自动封装
注意:sql语句后不要出现";"号
查询:select标签
增加:insert标签
修改:update标签
删除:delete标签
-->
</mapper>
注意:
- 因为我使用select * 查询字段,需要配置属性和字段的映射关系,使用<resultMap>标签
- #{}表示的是占位符的含义,这里使用它的含义和使用原生JDBC的preparedstatement预编译sql是一样的
- 当传入的参数为一个时,#{名字可以任意},如果传入的参数是多个,#{对应类的属性名}
第四步:将mapper.xml的配置添加到主配置文件mybatis.xml配置中
mybatis.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/csx_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
第五步:修改servlet类,使用mybatis获取sql支持
- 在doPost方法中通过SqlSessionfactory创建SqlSession对象,在根据SqlSession对象获取对应的Dao实现类对象(代理对象)。
- 调用Dao接口获取sql支持
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
SqlSession session= SqlSessionFactoryUtil.getSessionSql();
UserDao userDao= session.getMapper(UserDao.class);
//...
}
获取到Dao层的对象之后,获取到对应的数据之后。剩余处理就和未重构之前的操作一样了(细节处有点差异)。
简而言之,就是JSP发送请求到Servlet,Servlet调用DAO获取数据并处理响应。
总结
以上就是使用mybatis替代原生JDBC重构用户CRUD项目的实现步骤,源代码我会上传到资源中