一、Mybatis 概念介绍
MyBatis 是一款优秀的持久层(Dao)框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- 特点:
- 定制化SQL
- 支持存储过程(数据库脚本)调用
- 高级映射
二、ORM-对象关系映射
- 针对关系库 - 实体对象映射
- 表 实体类
- 字段 成员属性
- 表记录 类对象
三、自动化 VS 半自动化 ORM 框架
- 半自动化 ORM 框架:Mybatis
- 数据库表结构需要手动创建
- 依赖于数据库平台
- sql 语句需要开发人员编写
- 优势:
- sql 语句有开发人员编写 后期优化比较方便
- 适合传统项目 ,用于需求变化高的项目(互联网项目 电商 金融项目…)
- 市面用的最多的一套持久层框架
- 自动化ORM框架:Hibernate
- 可以通过框架来创建
- 不依赖具体的数据库平台
- 可以实现基本的CRUD 而不提供sql 直接调用API 方法即可
- 缺点:
- 表数据量较大时 查询效率比较低
- 用于需求变化不高的项目 传统型项目(OA 后端管理 ERP 系统…)
- 学习成本较高(实体与实体之间映射 sql 优化)
四、Mybatis 环境搭建与测试
1.创建Maven 普通项目
2.添加坐标
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- mybatis jar 包依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!-- log4j日志打印 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
</dependencies>
<build>
<!--
Maven 项目
如果源代码(src/main/java)存在xml properties tld 等文件,maven 默认不会自动编译该文件到输出目录
如果要编译源代码中xml properties tld 等文件,需要显式配置resources 标签
-->
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
<include>**/*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
3.添加日志log4j.properties 文件
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
4.添加全局配置文件 mybatis.xml
文件模板参考官网 https://mybatis.org/mybatis-3/zh/getting-started.html
<?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.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--
sql 映射文件 加载配置
-->
<mappers>
<mapper resource="com/xyz/mappers/UserMapper.xml"/>
</mappers>
</configuration>
5.添加sql 映射文件 UserMapper.xml
映射文件模本配置 https://mybatis.org/mybatis-3/zh/getting-started.html
<?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.xyz.mappers.UserMapper">
<!--
select 标签:查询标签
id:用于区分同一个xml 文件不同的标签 同文件下 标签id 值唯一
resultType:输出结果类型
parameterType:输入参数类型
标签体:待执行的sql 语句 #{}:参数占位符 类似于 原生的sql 中? 占位符
-->
<select id="queryUserByUserId" parameterType="int" resultType="com.xyz.vo.User">
select id, user_name as userName, user_pwd as userPwd, flag, create_time as createTime
from user
where id=#{id}
</select>
</mapper>
6.执行测试
@Test
public void test() throws IOException {
/**
a)、读取mybatis的配置文件
b)、加载配置文件创建SqlSessionFactory
c)、根据SqlSessionFactory创建SqlSession
d)、通过sqlSession操作数据库
e)、处理结果
f)、关闭session
*/
String file = "mybatis.xml";
InputStream is= Resources.getResourceAsStream(file);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession();
/**
* 参数1-statement:待执行的某个sql 对应的标签具体路径 namespace.标签id
* 参数2:参数值
*/
User user= session.selectOne("com.xyz.mappers.UserMapper.queryUserByUserId",75);
System.out.println(user);
session.close();
}
五、Mybatis 映射文件-输入输出参数
输入参数
- parameterType:
- 基本类型(4类8种)
- 常见类型(String、日期)
- JavaBean
- 集合(List 、Map)
- 数组
<!--
parameterType:输入参数类型 基本类型(四类八种) 常见类型(String 日期) JavaBean 集合(List Map) 数组
-->
<select id="queryUserByUserId" parameterType="int" resultType="User">
select id, user_name as userName, user_pwd as userPwd, flag, create_time as createTime
from user
where id=#{id}
</select>
<select id="queryUserByUserName" parameterType="string" resultType="User">
select id, user_name as userName, user_pwd as userPwd, flag, create_time as createTime
from user
where user_name=#{userName}
</select>
<select id="queryUserByUserNameAndUserPwd" parameterType="UserQuery" resultType="User">
select id, user_name as userName, user_pwd as userPwd, flag, create_time as createTime
from user
where user_name=#{userName} and user_pwd=#{userPwd}
</select>
<select id="queryUserByUserNameAndUserPwdMap" parameterType="map" resultType="User">
select id, user_name as userName, user_pwd as userPwd, flag, create_time as createTime
from user
where user_name=#{userName} and user_pwd=#{userPwd}
</select>
<delete id="deleteUsersByIds" >
delete from user where id in
<!-- collection:array|list -->
<foreach collection="array" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
<delete id="deleteUsersByIds02" >
delete from user where id in
<!-- collection:array|list -->
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
<delete id="deleteUsersByIds03" parameterType="map">
delete from user where id in
<!--
collection:array|list
如果参数类型为map:map key对应的value 为数组或list,此时collection值为key 名称
-->
<foreach collection="ids" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
输出参数(结果)
- resultType(输出结果类型):基本类型(四类八种) String|日期 JavaBean List Map List<Map>
- resultMap
<!--
resultType:输出结果类型 基本类型(四类八种) String|日期 JavaBean List Map List<Map>
-->
<sql id="user_columns">
id, user_name as userName, user_pwd as userPwd, flag, create_time as createTime
</sql>
<select id="queryUserNameById" parameterType="int" resultType="string">
select user_name from user where id=#{id}
</select>
<select id="queryUserIdByUserName" parameterType="string" resultType="int">
select id from user where user_name=#{userName}
</select>
<select id="queryUsersByUserName" parameterType="string" resultType="User">
select <include refid="user_columns"/> from user
where user_name like concat('%',#{userName},'%')
</select>
<select id="queryUserByIdMap" parameterType="int" resultType="map" >
select <include refid="user_columns"/> from user where id=#{id}
</select>
<select id="queryUsersByUserNameListMap" parameterType="string" resultType="map" >
select <include refid="user_columns"/> from user
where user_name like concat('%',#{userName},'%')
</select>
- Map List<Map>
- Map 5种遍历方式
Map<String,Object> result = session.selectOne("com.xyz.mappers.UserMapper.queryUserByIdMap",75);
System.out.println("---------------------");
for(String key: result.keySet()){
System.out.println(key+"--"+result.get(key));
}
System.out.println("---------------------");
for(Map.Entry<String,Object> entry:result.entrySet()){
System.out.println(entry.getKey()+"--"+entry.getValue());
}
System.out.println("---------------------");
result.keySet().forEach(k->{
System.out.println(k+"--"+result.get(k));
});
System.out.println("---------------------");
result.entrySet().forEach(e->{
System.out.println(e.getKey()+"--"+e.getValue());
});
System.out.println("---------------------");
result.forEach((k,v)->{
System.out.println(k+"--"+v);
});
-
- List<Map> 遍历
List<Map<String,Object>> results= session.selectList("com.xyz.mappers.UserMapper.queryUsersByUserNameListMap","test");
System.out.println("---------------------");
results.forEach(result->{
for(String key: result.keySet()){
System.out.println(key+"--"+result.get(key));
}
});
System.out.println("---------------------");
results.forEach(result->{
for(Map.Entry<String,Object> entry:result.entrySet()){
System.out.println(entry.getKey()+"--"+entry.getValue());
}
});
System.out.println("---------------------");
results.forEach(result->{
result.keySet().forEach(k->{
System.out.println(k+"--"+result.get(k));
});
});
System.out.println("---------------------");
results.forEach(result->{
result.entrySet().forEach(e->{
System.out.println(e.getKey()+"--"+e.getValue());
});
});
System.out.println("---------------------");
results.forEach(result->{
result.forEach((k,v)->{
System.out.println(k+"--"+v);
});
});
六、Mybatis CRUD 标签配置
- Select Insert Update Delete
<!--
insert:添加记录标签
添加记录返回影响行数
添加记录返回主键
批量添加
-->
<insert id="saveUser" parameterType="User" >
insert into user(user_name, user_pwd, flag, create_time)
values (#{userName},#{userPwd},#{flag},#{createTime})
</insert>
<!--
添加记录返回主键01
useGeneratedKeys:true mybatis 执行添加时 获取添加后的主键值
keyProperty:id 主键值 映射到User id 变量
-->
<insert id="saveUserHasKey" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into user(user_name, user_pwd, flag, create_time)
values (#{userName},#{userPwd},#{flag},#{createTime})
</insert>
<!--
添加记录返回主键02
添加字标签 selectKey
order:BEFORE|AFTER 指定获取主键在SQL执行前(BEFORE) 还是执行后(AFTER)
keyProperty
resultType
mysql
select last_insert_id()
oracle
SELECT LOGS_SEQ.nextval AS ID FROM DUAL
-->
<insert id="saveUserHasKey02" parameterType="User">
<selectKey order="AFTER" keyProperty="id" resultType="int">
select last_insert_id()
</selectKey>
insert into user(user_name, user_pwd, flag, create_time)
values (#{userName},#{userPwd},#{flag},#{createTime})
</insert>
<insert id="saveUserBatch" parameterType="list">
insert into user(user_name, user_pwd, flag, create_time) values
<foreach collection="list" item="item" separator=",">
(#{item.userName},#{item.userPwd},#{item.flag},#{item.createTime})
</foreach>
</insert>
<!--
update:
单条记录更新
批量更新
-->
<update id="updateUser" parameterType="User">
update user set user_name=#{userName},user_pwd=#{userPwd},flag=#{flag} where id=#{id}
</update>
<update id="updateUserPwdByIdsBatch" parameterType="map">
update user set user_pwd=#{userPwd}
where id in
<foreach collection="ids" item="item" open="(" separator="," close=")" >
#{item}
</foreach>
</update>
<delete id="deleteUsersByIds03" parameterType="map">
delete from user where id in
<!--
collection:array|list
如果参数类型为map map key对应的value 为数组或list 此时collection值为key 名称
-->
<foreach collection="ids" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
七、基于接口代理的CRUD(重点)
- 理解接口代理的CRUD 规范:
- mapper.xml中 namespace等于接口类全限定名
- mapper.java接口中的方法名必须与mapper.xml中statement id 一致
- mapper.java 输入参数类型必须与mapper.xml中statement 的parameterType参数类型一致
- mapper.java 中方法的返回值类型必须与mapper.xml 中对应statement 返回值类型一致。
- 接口名 与映射文件名称 一致(非集成环境)
- 映射文件与接口处于同一个包中(非集成环境)
1.定义接口(包 -com.xyz.mappers)
import com.xyz.query.AccountQuery;
import com.xyz.vo.Account;
import java.util.List;
public interface AccountMapper {
public Account queryAccountById(Integer id);
public List<Account> queryAccountsByParams(AccountQuery accountQuery);
}
2.定义映射文件(包 -com.xyz.mappers)
<?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.xyz.mappers.AccountMapper">
<sql id="account_columns">
id, aname, type, money, user_id as userId, create_time as createTime, update_time as updateTime, remark
</sql>
<select id="queryAccountById" parameterType="int" resultType="Account">
select <include refid="account_columns"/>
from account
where id=#{id}
</select>
<select id="queryAccountsByParams" parameterType="AccountQuery" resultType="com.xyz.vo.Account">
select <include refid="account_columns"/>
from account
where aname like concat('%',#{aname},'%') and type=#{type}
</select>
</mapper>
3.添加映射文件到全局文件mybatis.xml
<mappers>
<mapper resource="com/xyz/mappers/UserMapper.xml"/>
<mapper resource="com/xyz/mappers/AccountMapper.xml"></mapper>
</mappers>
4.执行测试
public class TestAccuntMapper {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
String file = "mybatis.xml";
InputStream is = Resources.getResourceAsStream(file);
factory = new SqlSessionFactoryBuilder().build(is);
}
@Test
public void test01() {
SqlSession session = factory.openSession();
// 获取接口的代理对象
AccountMapper accountMapperProxy = session.getMapper(AccountMapper.class);
Account account = accountMapperProxy.queryAccountById(142);
System.out.println(account);
session.close();
}
@Test
public void test02() {
SqlSession session = factory.openSession();
// 获取接口的代理对象
AccountMapper accountMapperProxy = session.getMapper(AccountMapper.class);
AccountQuery accountQuery=new AccountQuery();
accountQuery.setAname("test");
accountQuery.setType("1");
// 常用函数式接口 Consumer | BiConsumer | Predicate | Function
// 接口默认方法 foreach sort 默认方法
accountMapperProxy.queryAccountsByParams(accountQuery).forEach(a->{
System.out.println(a);
});
session.close();
}
}