唠嗑部分
上篇文章我们说了JDBC来操作数据库,已经可以在项目中完成部分功能了,在文章后续也留了JDBC高级部分,看过的伙伴们都知道,JDBC实现数据封装十分麻烦,我也尝试着用JDBC实现了ORM映射,但是缺乏专业的测评,项目中不可取,今天来说一下一款半自动化的ORM框架,Mybatis
总结一下,使用JDBC有什么缺点呢?
1、存在大量的冗余代码。
2、手工将结果集封装成实体对象。
3、查询效率低(都没有缓存的前提下,JDBC效率快),没有对数据访问进行过优化(Not Cache)
上面说ORM,那到底什么是ORM呢?
1、ORM(Object Relational Mapping)对象关系映射,将程序中的一个对象与表中的一行数据一一对应。
2、ORM框架提供了持久化类与表的映射关系,在运行时参照映射文件的信息,把对象持久化到数据库中。
浅谈Mybatis框架
1、源自于Apache的一个开源项目iBatis, 后改名为MyBatis
2、MyBatis是一个优秀的基于Java的持久层框架,支持自定义SQL,存储过程和高级映射。
3、MyBatis对原有JDBC操作进行了封装,几乎消除了所有JDBC代码,使开发者只需关注 SQL 本身。
4、MyBatis可以使用简单的XML或Annotation来配置执行SQL,并自动完成ORM操作,将执行结果返回。
内容介绍
一、简单入门案例
1、构建环境,创建数据库&初始化数据
create database `mybatis-wx-demo` character set 'utf8mb4';
use `mybatis-wx-demo`;
create table user
(
id int primary key auto_increment comment '主键id',
user_name varchar(255) comment '用户名',
age int comment '年龄',
create_time datetime comment '创建时间'
) comment '用户表';
insert into user values (1, '全栈小白', 23, CURRENT_TIMESTAMP()),
(2, '南宫飞雪', 25, CURRENT_TIMESTAMP()),
(3, '盒马鲜生', 30, CURRENT_TIMESTAMP());
2、创建Maven项目&导入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
3、创建核心配置文件
<?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">
<!--MyBatis配置-->
<configuration>
<!--添加properties配置文件路径(外部配置、动态替换)-->
<properties resource="db.properties" />
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--JDBC环境配置、选中默认环境-->
<environments default="MySqlDB">
<!--MySql数据库环境配置-->
<environment id="MySqlDB">
<!--事务管理-->
<transactionManager type="JDBC"/>
<!--连接池-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--Mapper注册-->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
4、创建实体类
/**
* @Project: mybatis-wx-demo
* @Author: cxs2014501@163.com
* @Create: 2023/2/28 10:41
* @Description:
**/
@Data
public class User {
private Integer id;
private String userName;
private Integer age;
private LocalDateTime createTime;
}
5、创建UserMapper接口
/**
* @Project: mybatis-wx-demo
* @Author: cxs2014501@163.com
* @Create: 2023/2/28 10:41
* @Description:
**/
public interface UserMapper {
/**
* 根据id查询
* @param id
* @return
*/
User selectById(Integer id);
}
6、创建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">
<!--namespace = 所需实现的接口全限定名-->
<mapper namespace="com.cxs.mapper.UserMapper">
<!--id = 所需重写的接口抽象方法,resultType = 查询后所需返回的对象类型-->
<select id="selectById" resultType="com.cxs.model.User">
<!--#{arg0} = 方法的第一个形参-->
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
7、测试
/**
* @Project: mybatis-wx-demo
* @Author: cxs2014501@163.com
* @Create: 2023/2/28 10:46
* @Description:
**/
public class UserMapperTest {
@Test
public void selectById() throws IOException {
//1.获得读取MyBatis配置文件的流对象
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.构建SqlSession连接对象的工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂获得连接对象
SqlSession sqlSession = factory.openSession();
//4.通过连接对象获得接口实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//5.调用接口中的方法
System.out.println(userMapper.selectById(1));
}
}
二、Mybatis实现CRUD-查询
2.1 序号参数绑定
public interface UserMapper {
public User selectUserByIdAndAge(Integer id , Integer age);
}
<select id="selectUserByIdAndAge" resultType="user">
SELECT * FROM user
WHERE id = #{arg0} AND age = #{arg1} <!--arg0 arg1 arg2 ...-->
</select>
<select id="selectUserByIdAndAge" resultType="user">
SELECT * FROM user
WHERE id = #{param1} AND age = #{param2} <!--param1 param2 param3 ...-->
</select>
2.2 注解参数绑定【推荐】
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
//使用MyBatis提供的@Param进行参数绑定
public User selectUserByIdAndPwd(@Param("id") Integer id , @Param("age") Integer age);
}
<select id="selectUserByIdAndAge" resultType="user">
SELECT * FROM user
WHERE id = #{id} AND age = #{age} <!-- 使用注解值 @Param("pwd") -->
</select>
2.3 Map参数绑定
public interface UserMapper {
//添加Map进行参数绑定
public User selectUserByIdAndPwd_map(Map values);
}
Map values = new HashMap();
values.put("age",1);
User user = UserMapper.selectUserByAge(values);
<select id="selectUserByAge" resultType="user">
SELECT * FROM user
WHERE age = #{age} <!-- 通过key获得value -->
</select>
2.4 对象参数绑定
public interface UserMapper {
//使用对象属性进行参数绑定
public User selectUserByUserInfo(User user);
}
<select id="selectUserByUserInfo" resultType="user">
SELECT * FROM user
WHERE id = #{id} AND age = #{age} <!-- #{id}取User对象的id属性值、#{age}同理 -->
</select>
2.5 模糊查询
public interface UserMapper {
public List<User> selectUsersByKeyword(@Param("keyword") String keyword);
}
<mapper namespace="com.cxs.mybatis.part1.different.UserMapper">
<select id="selectUsersByKeyword" resultType="user">
SELECT * FROM user
WHERE name LIKE concat('%',#{keyword},'%') <!-- 拼接'%' -->
</select>
</mapper>
三、Mybatis实现CRUD-删除
标签:< delete id=“” parameterType=“” >
<delete id="deleteUser" parameterType="int">
DELETE FROM user
WHERE id = #{id} <!--只有一个参数时,#{任意书写}-->
</delete>
四、Mybatis实现CRUD-修改
标签:< update id=“” parameterType=“” >
<update id="updateUser" parameterType="user">
UPDATE user SET user_name=#{userName}, age=#{age}, create_time=#{createTime}
WHERE id = #{id}
</update>
五、Mybatis实现CRUD-添加
标签:< insert id=“” parameterType=“” >
<!--手动主键-->
<insert id="insertUser" parameterType="user">
INSERT INTO user VALUES(#{id},#{userName},#{age},#{createTime});
</insert>
<!--自动主键-->
<insert id="insertUser" parameterType="user">
<!-- 自动增长主键,以下两种方案均可 -->
INSERT INTO user VALUES(null,#{userName},#{age},#{createTime});
</insert>
六、Mybatis-主键回填
标签:< selectKey id=“” parameterType=“” order=“AFTER|BEFORE”>
<mapper namespace="com.cxs.mapper.UserMapper">
<insert id="insertUser" parameterType="user">
<selectKey keyProperty="id" resultType="int" order="AFTER"> <!-- 插入之后 -->
SELECT LAST_INSERT_ID() <!-- 适用于整数类型自增主键 -->
</selectKey>
INSERT INTO user VALUES(#{id},#{userName},#{age},#{createTime});
</insert>
</mapper>
七、MyBatis工具类封装
package com.cxs.utils;
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.InputStream;
public class MyBatisUtils {
//获得SqlSession工厂
private static SqlSessionFactory factory;
//创建ThreadLocal绑定当前线程中的SqlSession对象
private static final ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();
static {
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (Exception e) {
e.printStackTrace();
}
}
//获得连接(从tl中获得当前线程SqlSession)
private static SqlSession openSession(){
SqlSession session = tl.get();
if(session == null){
session = factory.openSession();
tl.set(session);
}
return session;
}
//释放连接(释放当前线程中的SqlSession)
private static void closeSession(){
SqlSession session = tl.get();
session.close();
tl.remove();
}
//提交事务(提交当前线程中的SqlSession所管理的事务)
public static void commit(){
SqlSession session = openSession();
session.commit();
closeSession();
}
//回滚事务(回滚当前线程中的SqlSession所管理的事务)
public static void rollback(){
SqlSession session = openSession();
session.rollback();
closeSession();
}
//获得接口实现类对象
public static <T extends Object> T getMapper(Class<T> clazz){
SqlSession session = openSession();
return session.getMapper(clazz);
}
}
结语
本文介绍简单的CRUD操作,关于Mybatis的其他内容会持续更新