20-506暑期培训Mybatis
Ⅰ.准备
数据库:MySQL 8.0+
工具:idea+maven
导入maven依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
Ⅱ.mybatis概述
简单地说mybatis就是一个简化jdbc操作的工具,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Ⅲ.工作原理
首先我们要先创建一个SqlSessionFactoryBuilder实例,这个对象有什么用呢? 他可以通过读入主配置文件流来建立一个SqlSessionFactory,用于生产SqlSession对象,然后再通过获得的SqlSession执行各个映射文件中的sql语句。大致原理如下图
1.主配置文件(MybatisConfig.xml)
Mybatis的全局配置文件,主要用于配置Mybatis的运行环境(事务管理器、数据源、映射文件路径等)下面通过一个简单的示例,来简要说明这个配置文件。
<?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>
<!--类型别名,有了这个在Mapper里面写映射类的时候就不用写全名了-->
<typeAliases>
<package name="com.wfh.bean"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--使用连接池连接数据库-->
<dataSource type="POOLED">
<property name="driver" value="
"/>
<property name="url" value=""/>
<property name="username" value=""/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<mappers>
<!--这里配置各Mapper的位置-->
</mappers>
</configuration>
这里提一下数据源类型共有下列几种:
“UNPOOLED”:不使用数据库连接池。使用传统链接方法,每次建立操作数据库都需要打开、关闭连接。
“POOLED”:使用数据库连接池。这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
“JNDI”:为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。
指定Mapper文件位置的写法主要有三种:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
2.数据库映射文件(Mapper.xml)
Mapper映射文件是我们写sql语句的地方,我们把写好的语句放到Mapper文件中保存方面之后的调用,下面是Mapper文件的大体结构
<?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="xxx">
<select id="s1">
<!--写sql语句的地方-->
</select>
<insert id="i1">
<!--写sql语句的地方-->
</insert>
<delete id="d1">
<!--写sql语句的地方-->
</delete>
<update id="u1">
<!--写sql语句的地方-->
</update>
</mapper>
和主配置文件一样,映射文件也有各约束文档,其正文的mapper标签需要一个namespace属性用作唯一标识,然后再该标签内添加各种CURD相关操作的标签
3.数据库配置文件(db.properties)
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/dbname?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root
用于存放jdbc相关配置信息
有了这个文件,主配置文件中关于数据库连接的配置就可以写成这样
<!--现在configuration标签中引入配置文件-->
<properties resource="db.properties"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
4.日志配置文件(log4j.properties)
原始的Mybatis对数据库的查询总是伴随着日志记录输出,这个配置文件是必要的,否则会运行出错(不用了解原理,复制过去就行)
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
Ⅳ.操作样例
数据表和映射类
在进行基础的数据库操作之前,我们首先需要一些必要的文件——数据表和映射类
数据表:user
对应的映射类:com.wfh.bean.User
public class User {
private Integer u_id;
private String u_username;
private String u_password;
private String u_sex;
private Date u_createTime;
public Integer getU_id() {
return u_id;
}
public void setU_id(Integer u_id) {
this.u_id = u_id;
}
public String getU_username() {
return u_username;
}
public void setU_username(String u_username) {
this.u_username = u_username;
}
public String getU_password() {
return u_password;
}
public void setU_password(String u_password) {
this.u_password = u_password;
}
public String getU_sex() {
return u_sex;
}
public void setU_sex(String u_sex) {
this.u_sex = u_sex;
}
public Date getU_createTime() {
return u_createTime;
}
public void setU_createTime(Date u_createTime) {
this.u_createTime = u_createTime;
}
@Override
public String toString() {
return "User{" +
"u_id=" + u_id +
", u_username='" + u_username + '\'' +
", u_password='" + u_password + '\'' +
", u_sex='" + u_sex + '\'' +
", u_createtime=" + u_createtime +
'}';
}
}
需要注意的是这里映射类的属性名一定要和数据表中的字段值一致;
编写测试类
上述各配置文件的模板已经有了,我们只需要按照自己的需求修改一下,当然在那之前还需要先确定一下文件结构----在resources文件夹下创建mappers目录用于存放各映射文件Mapper,然后把db.properties、log4j.properties、主配置文件等与mappers目录位于同一级目录下
最后在创建一个测试类Main,添加main方法,创建好所需要的工具类用于数据库操作
public class Main {
public static void main(String[] args) throws IOException {
//将主配置文件读取为输入流
InputStream in=Resources.getResourceAsStream("MybatisConfig.xml");
//创建工厂生产者
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
//生成工厂
SqlSessionFactory factory = builder.build(in);
//获取session
SqlSession session = factory.openSession();
}
}
1.查
对应select标签,标签的id和Mapper的namespace组合成sql语句的唯一表示,方便session调用。
根据id查询用户
<!--xml-->
<select id="selectById" parameterType="Integer" resultType="User">
<!--#{}中的变量为参数,名字可任意-->
select * from user where u_id=#{id}
</select>
//java
User user = session.selectOne("Mapper1.selectById", 1);
System.out.println(user);
selectOne()方法用于查询返回结果是单个的情况,第一个参数就是sql语句的唯一标签namespace.id,第二个参数用昨筛选条件的参数,如此处的筛选条件为id=1,如果没有筛选条件可省略
查询所有用户
<!--tip:虽然最后我们使用List类型接收返回结果,但是此处的resultType还得是User-->
<select id="selectAll" resultType="User">
select * from user
</select>
//java
List<User> userList=session.selectList("Mapper1.selectAll");
for(User u:userList){
System.out.println(u);
}
selectList()方法用于查询返回结果有多条记录的情况,参数同上
2.增
对应insert标签,如果我们需要插入一条包含用户名、密码、性别、注册时间的记录,这些参数的类型各不相同,而传入不同类型参数是我们可以直接传入一个包含这些参数的类(也就是我们这里的User类),并且要让sql语句中的参数名要与类中的成员变量名一致。
<!--xml-->
<insert id="insertUser" parameterType="User">
insert into user values (null,#{u_username},#{u_password},#{u_sex},#{u_createTime});
</insert>
User u=new User();
u.setU_username("老陈");
u.setU_password("456");
u.setU_sex("男");
u.setU_createTime(new Date());
session.insert("Mapper1.insertUser",u);
session.commit();
注意:因为session中执行的对数据库的操作语句都被视为事务级别,所以不提交是不会有任何变化的,最后需要执行commit()方法,并且如果中间有异常出错,数据库也不会更改
3.删
对应的标签为delete,其他过程与上述操作相同,如下
<delete id="deleteUser" parameterType="Integer">
delete from user where u_id=#{id}
</delete>
session.delete("deleteUser",1);
session.commit();
4.改
对应的标签为update
根据id更改姓名
<update id="updateUser" parameterType="User">
update user set u_username=#{u_username} where u_id=#{u_id}
</update>
User u=new User();
u.setU_id(1);
u.setU_username("王富贵");
session.update("updateUser",u);
session.commit();
在做update操作时我们可以只为对象设置sql语句中需要的参数的相关属性,因为别的属性也不会去管
Ⅴ.映射文件绑定接口
在上述样例中,我们执行的所有增删改查操作都是用一个SQLsession来完成的,这样做有一个缺点就是,如果数据表多了,我们在代码角度就很难看出来具体哪个语句是对哪个表做操作的,各个Mapper映射文件的分工就很不清晰,所以mybatis就引入了接口与映射文件绑定的这种方法
我们在com.wfh包下创建一个dao包,在这个包下创建一个UserMapper(或者叫UserDao)接口
然后在UserMapper.xml中将mapper的namespace指定为这个接口的全包名
然后在这个接口类中,将mapper里的各标签声明为一个方法,方法名要与标签id一致,且参数类型、返回类型都要与mapper文件中的一致,具体如下
public interface UserDao {
User selectById(Integer id);
List<User> selectAll();
void insertUser(User user);
void deleteUser(Integer id);
void updateUser(User user);
}
这样之后,我们要执行mapper中的sql语句就可以这么用
UserDao dao=session.getMapper(UserDao.class);
//增
User u1=new User();
u1.setU_username("老三");
u1.setU_password("506");
u1.setU_sex("男");
u1.setU_createTime(new Date());
dao.insertUser(u1);
//删
dao.deleteUser(1);
//改
User u2=new User();
u2.setU_id(1);
u2.setU_username("王富贵");
dao.updateUser(u2);
//查
List<User> userList = dao.selectAll();
User u3=dao.selectById(1);
Ⅵ.MybatisGenerator
接下来我们要学习一个非常有用的工具—MybatisGenerator(以下称MBG);它可以自动的根据数据库的表生成对应的数据库映射类、接口以及Mapper.xml文件,你只要告知它一些规则就可以了,非常的方便。具体操作请见
https://blog.csdn.net/ifffff/article/details/109358855
下面大概讲一下MBG生成的文件
User类
与我们之前写的User不同的是,他并不是与数据表中的字段名一模一样,而是将字段名中的下划线去掉,然后后面紧跟着的字母大写,如 u_id->uId,u_username->uUsername
UserMapper.java
MBG生成的接口类中大部分都是六个方法,如下
public interface UserMapper {
//根据主键删除
int deleteByPrimaryKey(Integer uId);
//插入数据
int insert(User record);
//选择性插入
int insertSelective(User record);
//根据主键查找
User selectByPrimaryKey(Integer uId);
//根据主键选择性更改内容
int updateByPrimaryKeySelective(User record);
//根据属性更改内容
int updateByPrimaryKey(User record);
}
这里解释一下什么是选择性,比如选择性更改updateByPrimaryKeySelective,他会一边检查传入的record对象的属性一边做修改,如果对应的属性值为空,就不对其字段进行修改。
那么他具体是怎么实现的呢,我们来看一下Mapper.xml文件
UserMapper.xml
结果集
MBG生成的映射类的属性名并没有与表字段名完全一致却能正常工作,就是因为在映射文件中加入了结果集,将字段名与属性名做了映射。有了结果集更能够满足开发者需求,字段映射也更加精准。
语句包含
sql标签可以用于将各标签中重复的语句提取并保存起来,需要的时候可以用include标签调用
<sql id="Base_Column_List">
u_id, u_username, u_password, u_sex, u_createTime
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user
where u_id = #{uId,jdbcType=INTEGER}
</select>
如上述语句最终生成的结果就是
select
u_id, u_username, u_password, u_sex, u_createTime
from user
where u_id = #{uId,jdbcType=INTEGER}