1. Mybatis的基本使用
1. 前提条件
mybatis操作数据库需要一个实体类和数据库表字段一一对应。
2. 导入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
3. 创建数据库表和实体类
-
创建数据库表
CREATE TABLE `user` ( `id` int(11) NOT NULL auto_increment, `username` varchar(32) NOT NULL COMMENT '用户名称', `birthday` datetime default NULL COMMENT '生日', `sex` char(1) default NULL COMMENT '性别', `address` varchar(256) default NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
创建对应的实体类
- 使用lombok工具
import lombok.Builder; import lombok.Data; import java.util.Date; @Builder public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; public User() { } public User(Integer id, String username, Date birthday, String sex, String address) { this.id = id; this.username = username; this.birthday = birthday; this.sex = sex; this.address = address; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}'; } }
4. dao层接口和编写sql语句的xml文件
- dao接口
import java.io.Serializable;
import java.util.List;
public interface UserDao<T> extends Serializable {
/**
* 查询所有
* @return 符合条件的list集合
*/
public List<T> selectAll();
}
-
对象的接口的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 namespace="com.kl.dao.UserDao"> <!-- xml配置文件中的关键字说明 namespace: 名称空间,表示该配置文件操作那个dao接口 id: dao接口中对应的方法名 resultType: 返回的结果封装为什么类型 --> <!-- 查询所有 --> <select id="selectAll" resultType="com.kl.bean.User"> select id,username,birthday,sex,address from user </select> </mapper>
5. Mybatis的配置文件(SqlMapConfig.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">
<!-- mybatis的主配置文件 -->
<configuration>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.0.113:3306/mybatis?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
<mappers>
<mapper resource="com/kl/dao/userDao.xml"/>
</mappers>
</configuration>
6. 单元测试
import com.kl.bean.User;
import com.kl.dao.UserDao;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MybatisTest {
public static InputStream in = null;
public static SqlSessionFactoryBuilder builder = null;
public static SqlSession session = null;
/**
* 测试开始时执行
*/
@Before
public void beforeTest() throws IOException {
System.out.println("测试开始...");
// 1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.创建SqlSessionFactory工厂
builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
// 3.使用工厂生产SqlSession对象
session = factory.openSession();
}
/**
* 测试最后执行的方法
*/
@After
public void afterTest() throws IOException {
// 提交事务
session.commit();
// 释放资源
session.close();
in.close();
System.out.println("测试结束...");
}
/**
* 测试查询所有
*/
@Test
public void selectAllTest(){
// 使用SqlSession创建Dao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 使用代理对象执行方法
List<User> users = userDao.selectAll();
for (User user : users) {
System.out.println(user);
}
}
}
2. Mybatis的CRUD
1. dao层接口
import com.kl.bean.User;
import java.io.Serializable;
import java.util.List;
/**
* 用户持久层接口
*/
public interface UserDao<T> extends Serializable {
/**
* 添加
* @param t 添加的数据类型
* @return 影响的行数
*/
public int insert(T t);
/**
* 根据id删除数据
* @param id 删除数据对应的id
* @return 影响的行数
*/
public int deleteById(int id);
/**
* 根据传入的id集合进行批量删除
* @param ids id集合
* @return 返回删除的记录条数
*/
public int deleteBatchById(List<Integer> list);
/**
* 根据id更新
* @param t 需要对象
* @return 更新的行数
*/
public int updateById(T t);
/**
* 根据id查询
* @param id 查询的数据对应的id
* @return 符合条件的对象
*/
public <T> T selectById(int id);
/**
* 模糊查询
* @return 符合条件的list集合
*/
public List<T> selectByLikeByIf(User user);
/**
* 条件查询使用if标签
* @param user 传入查询对象
* @return 符合条件的list集合
*/
public List<T> selectByCondition(User user);
/**
* 条件查询使用if标签和where标签
* @param user 传入查询对象
* @return 符合条件的list集合
*/
public List<T> selectByLikeByIfAndWhere(User user);
/**
* 查询所有
* @return list集合
*/
public List<T> selectAll();
/**
* count() 聚合函数的使用
* @return list集合
*/
public int count();
}
2. 对应的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 namespace="com.kl.dao.UserDao">
<!--
xml配置文件中的关键字说明
namespace :名称空间,表示该配置文件操作那个dao接口,全限定类名
id :dao接口中对应的方法名,全限定类名
parameterType : 传入参数的类型,写参数的全限定类名
resultType : 返回的结果封装的类型,全限定类名
#{} : 用于接收传递进来的参数
-->
<!-- 基础的查询字段封装 -->
<sql id="baseSelectSql">
select id, username, birthday, sex, address
</sql>
<!-- 添加 -->
<insert id="insert" parameterType="com.kl.bean.User">
<!--
配置数据主键自动增长情况下添加数据成功后返回的主键:selectKey标签
keyProperty:对应实体类的key
keyColumn :对应数据库表的key
resultType :返回的类型
order :什么时候返回 AFTER:执行了添加操作之后,BEFORE:执行添加操作之前
-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert
into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 根据id删除 -->
<delete id="deleteById" parameterType="int">
delete
from user
where id = #{id}
</delete>
<!--
根据传入的id集合进行批量删除
foreach :
collection :代表要遍历的集合元素,注意编写时不要写#{}
open :代表语句的开始部分
close :代表结束部分
item :代表遍历集合的每个元素,生成的变量名
separator :代表分隔符
注意:parameterType中如果传递的参数名字为list或者其他的集合
则在使用到list集合的地方必须要使用list变量名,不然mybatis无法识别
-->
<delete id="deleteBatchById" parameterType="list">
delete
from user
<where>
<if test="list != null and list.size() > 0">
<foreach collection="list" open="and id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</delete>
<!-- 根据id修改 -->
<update id="updateById" parameterType="com.kl.bean.User">
update user
set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address}
where id = #{id}
</update>
<!-- 根据id查询 -->
<select id="selectById" parameterType="int" resultType="com.kl.bean.User">
<include refid="baseSelectSql"/>
from user
where id = #{id}
</select>
<!-- 条件查询使用if标签 -->
<select id="selectByLikeByIf" parameterType="com.kl.bean.User" resultType="com.kl.bean.User">
<include refid="baseSelectSql"/>
from user
where 1 = 1
<if test="username != null and username != '' ">
and username like #{username}
</if>
<if test="birthday != null and birthday != '' ">
and birthday like #{birthday}
</if>
<if test="sex != null and sex != '' ">
and sex like #{sex}
</if>
<if test="address != null and address != '' ">
and address like #{address}
</if>
</select>
<!-- 条件查询使用if标签和where标签 -->
<select id="selectByLikeByIfAndWhere" parameterType="com.kl.bean.User" resultType="com.kl.bean.User">
<include refid="baseSelectSql"/>
from user
<where>
<if test="username != null and username != '' ">
and username like #{username}
</if>
<if test="birthday != null and birthday != '' ">
and birthday like #{birthday}
</if>
<if test="sex != null and sex != '' ">
and sex like #{sex}
</if>
<if test="address != null and address != '' ">
and address like #{address}
</if>
</where>
</select>
<!-- 条件分页查询 -->
<select id="selectByCondition" resultType="com.kl.bean.User">
<include refid="baseSelectSql"/>
from user
<where>
<if test="username != null and username != '' ">
and username like #{username}
</if>
<if test="birthday != null and birthday != '' ">
and birthday like #{birthday}
</if>
<if test="sex != null and sex != '' ">
and sex like #{sex}
</if>
<if test="address != null and address != '' ">
and address like #{address}
</if>
</where>
limit 0,5
</select>
<!-- 查询所有 -->
<select id="selectAll" resultType="com.kl.bean.User">
<include refid="baseSelectSql"/>
from user
</select>
<!-- count() 聚合函数的使用 -->
<select id="count" resultType="int">
select count(*)
from user;
</select>
</mapper>
3. 单元测试类
import com.kl.bean.User;
import com.kl.dao.UserDao;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 测试mybatis
*/
public class MybatisTest {
public static InputStream in = null;
public static SqlSessionFactoryBuilder builder = null;
public static SqlSession session = null;
/**
* 测试开始时执行
*/
@Before
public void beforeTest() throws IOException {
System.out.println("测试开始...");
// 1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.创建SqlSessionFactory工厂
builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
// 3.使用工厂生产SqlSession对象
session = factory.openSession();
}
/**
* 测试最后执行的方法
*/
@After
public void afterTest() throws IOException {
// 提交事务
session.commit();
// 释放资源
session.close();
in.close();
System.out.println("测试结束...");
}
/**
* 添加
*/
@Test
public void insertTest(){
// 使用SqlSession创建Dao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 创建一个User对象,用于添加操作
User user = User.builder()
.username("名字")
.birthday(new Date())
.sex("男")
.address("地址")
.build();
System.out.println("添加前...");
System.out.println(user);
int count = userDao.insert(user);
System.out.println(count);
System.out.println("添加后...");
System.out.println(user);
}
/**
* 根据id删除数据
*/
@Test
public void deleteByIdTest(){
UserDao userDao = session.getMapper(UserDao.class);
int count = userDao.deleteById(53);
System.out.println(count);
}
/**
* 根据id删除数据
*/
@Test
public void deleteBatchByIdTest(){
UserDao userDao = session.getMapper(UserDao.class);
List<Integer> list = new ArrayList<Integer>();
list.add(67);
list.add(68);
list.add(69);
list.add(70);
int count = userDao.deleteBatchById(list);
System.out.println(count);
}
/**
* 根据id更新
*/
@Test
public void updateByIdTest(){
UserDao userDao = session.getMapper(UserDao.class);
User user = User
.builder()
.id(53)
.username("测试修改")
.birthday(new Date())
.sex("男")
.address("地址")
.build();
int count = userDao.updateById(user);
System.out.println(count);
}
/**
* 根据id查询
*/
@Test
public void selectByIdTest(){
UserDao userDao = session.getMapper(UserDao.class);
User user = (User) userDao.selectById(41);
System.out.println(user);
}
/**
* 根据id查询
*/
@Test
public void selectByLikeByIfTest(){
UserDao userDao = session.getMapper(UserDao.class);
User userVo = User
.builder()
.username("%小%")
.address("%金%")
.build();
List<User> users = userDao.selectByLikeByIf(userVo);
for (User user : users) {
System.out.println(user);
}
}
/**
* 条件查询使用if标签和where标签
*/
@Test
public void selectByLikeByIfAndWhereTest(){
UserDao userDao = session.getMapper(UserDao.class);
User userVo = User
.builder()
.username("%小%")
.address("%金%")
.build();
List<User> users = userDao.selectByLikeByIfAndWhere(userVo);
for (User user : users) {
System.out.println(user);
}
}
/**
* 条件查询使用if标签和where标签
*/
@Test
public void selectByConditionTest(){
UserDao userDao = session.getMapper(UserDao.class);
User userVo = new User();
List<User> users = userDao.selectByCondition(userVo);
for (User user : users) {
System.out.println(user);
}
}
/**
* 测试查询所有
*/
@Test
public void selectAllTest(){
// 使用SqlSession创建Dao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 使用代理对象执行方法
List<User> users = userDao.selectAll();
for (User user : users) {
System.out.println(user);
}
}
/**
* count() 聚合函数的使用
*/
@Test
public void countTest(){
// 使用SqlSession创建Dao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 使用代理对象执行方法
int count = userDao.count();
System.out.println(count);
}
}
3. #{ }与${ }的区别
-
{ }表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,
#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类
型值,#{}括号中可以是 value 或其它名称。
-
${}表示拼接 sql 串
通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简
单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。
4. 动态SQL标签
1. if 标签
- 基本概念:当在where条件后面跟的字段不确定是否存着时,可以使用if标签,当字段存入的字段不为null时才拼接到查询条件的后面。否则不拼接。
1. dao层代码
/**
* 模糊查询
* @return 符合条件的list集合
*/
public List<T> selectByLike(User user);
2. xml映射配置文件
<!-- 模糊查询 -->
<select id="selectByLike" parameterType="com.kl.bean.User" resultType="com.kl.bean.User">
select id,username,birthday,sex,address
from user
where 1 = 1
<if test="username != null and username != '' ">
and username like #{username}
</if>
<if test="birthday != null and birthday != '' ">
and birthday like #{birthday}
</if>
<if test="sex != null and sex != '' ">
and sex like #{sex}
</if>
<if test="address != null and address != '' ">
and address like #{address}
</if>
</select>
3. 单元测试
/**
* 根据id查询
*/
@Test
public void selectByLikeTest(){
UserDao userDao = session.getMapper(UserDao.class);
User userVo = User
.builder()
.username("%小%")
.address("%金%")
.build();
List<User> users = userDao.selectByLike(userVo);
for (User user : users) {
System.out.println(user);
}
}
2. where标签
- 目的:为了简化 where 1=1 的条件拼装,我们可以采用 where 标签来简化开发
1. dao层接口
/**
* 条件查询使用if标签和where标签
* @param user 传入查询对象
* @return 符合条件的list集合
*/
public List<T> selectByLikeByIfAndWhere(User user);
2. xml映射配置文件
<!-- 条件查询使用if标签和where标签 -->
<select id="selectByLikeByIfAndWhere" parameterType="com.kl.bean.User" resultType="com.kl.bean.User">
select id,username,birthday,sex,address
from user
<where>
<if test="username != null and username != '' ">
and username like #{username}
</if>
<if test="birthday != null and birthday != '' ">
and birthday like #{birthday}
</if>
<if test="sex != null and sex != '' ">
and sex like #{sex}
</if>
<if test="address != null and address != '' ">
and address like #{address}
</if>
</where>
</select>
3. 单元测试
/**
* 条件查询使用if标签和where标签
*/
@Test
public void selectByLikeByIfAndWhereTest(){
UserDao userDao = session.getMapper(UserDao.class);
User userVo = User
.builder()
.username("%小%")
.address("%金%")
.build();
List<User> users = userDao.selectByLikeByIfAndWhere(userVo);
for (User user : users) {
System.out.println(user);
}
}
3. foreach 标签
- 作用:用于解析传入进来的集合参数
- 使用foreach 遍历传入的list集合,根据得到的id进行数据删除
1. dao层接口
/**
* 根据传入的id集合进行批量删除
* @param ids id集合
* @return 返回删除的记录条数
*/
public int deleteBatchById(List<Integer> list);
2. xml映射配置文件
<!--
根据传入的id集合进行批量删除
foreach :
collection :代表要遍历的集合元素,注意编写时不要写#{}
open :代表语句的开始部分
close :代表结束部分
item :代表遍历集合的每个元素,生成的变量名
separator :代表分隔符
注意:parameterType中如果传递的参数名字为list或者其他的集合
则在使用到list集合的地方必须要使用list变量名,不然mybatis无法识别
-->
<delete id="deleteBatchById" parameterType="list">
delete
from user
<where>
<if test="list != null and list.size() > 0">
<foreach collection="list" open="and id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</delete>
3. 单元测试
/**
* 根据id删除数据
*/
@Test
public void deleteBatchByIdTest(){
UserDao userDao = session.getMapper(UserDao.class);
List<Integer> list = new ArrayList<Integer>();
list.add(67);
list.add(68);
list.add(69);
list.add(70);
int count = userDao.deleteBatchById(list);
System.out.println(count);
}
5. Mybatis中的sql片段简化
- 当重复的sql出现的次数过多时,可以重复的sql语句进行抽取出来,使用是再使用include标签进行引入即可。
- 例如:
- 将需要查询的字段进行封装
1. xml映射配置文件
<!-- 基础的查询字段封装 -->
<sql id="baseSelectSql">
select id, username, birthday, sex, address
</sql>
<!-- 使用基础的查询字段封装 -->
<!-- 查询所有 -->
<select id="selectAll" resultType="com.kl.bean.User">
<include refid="baseSelectSql"/>
from user
</select>
6. 聚合函数的使用
1. count() 函数
- 作用:统计查询到数据的数量,
- count(*):统计所有的包括null
- count(具体字段):统计的次数不包括null
1. dao层接口
/**
* count() 聚合函数的使用
* @return list集合
*/
public int count();
2. xml映射配置文件
<!-- count() 聚合函数的使用 -->
<select id="count" resultType="int">
select count(*)
from user;
</select>
4. 单元测试
/**
* count() 聚合函数的使用
*/
@Test
public void countTest(){
// 使用SqlSession创建Dao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 使用代理对象执行方法
int count = userDao.count();
System.out.println(count);
}