标签等同于 where 1=1
select * from user
<where>
<if test="id!=null">
and id=#{id}
if>
<if test="username!=null">
and username=#{username}
if>
<if test="password!=null">
and password=#{password}
if>
where>
等同于
select * from user where 1=1
<if test="id!=null">
and id=#{id}
if>
<if test="username!=null">
and username=#{username}
if>
<if test="password!=null">
and password=#{password}
if>
需求
传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)
SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。
这样我们将如何进行参数的传递?
UserDao代码添加方法
/**
* 根据多个id进行查询 至于是几个id不确定 可以使用集合 也可以使用数组
* @param ids
* @return
*/
List<User> findInIds(List<Integer> ids);
循环执行sql的拼接操作,例如:SELECT * FROM USER WHERE id IN (1,2,5)。
xml文件代码
<select id="findInIds" resultType="user">
<include refid="selectUser">include>
<where>
<foreach collection="list" open="id in (" close=")" item="id" separator=",">
#{id}
foreach>
where>
select>
测试代码
@Test
public void testFindInIds(){
// 动态的传输id数据
List<Integer> list = new ArrayList<Integer>();
list.add(43);
list.add(46);
list.add(48);
List<User> userList = userDao.findInIds(list);
for (User user : userList) {
System.out.println(user);
}
}
运行结果

Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
<sql id="selectUser">
select * from user
sql>
<select id="findInIds" resultType="user">
<include refid="selectUser">include>
<where>
<foreach collection="list" open="id in (" close=")" item="id" separator=",">
#{id}
foreach>
where>
select>
typeHandler 作用
由于Java 类型和数据库的 JDBC 类型不是一一对应的(比如 String 与 varchar), 所以我们把 Java 对象转换为数据库的值,和把数据库的值转换成 Java 对象,需要经过 一定的转换,这两个方向的转换就要用到 TypeHandler,那么有人可能在想了,我们平时没有做任何关于TypeHandler的配置,为什么实体类对象里面的String属性,可以保存成数据库里面的varchar字段或者保存成char字段呢,这是因为MyBatis中已经内置了很多TypeHandler。
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器(截取部分)。

你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个JDBC类型。例如需求:一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date,即java的Date与数据库的varchar毫秒值之间转换。
开发步骤:
①定义转换类继承类BaseTypeHandler
②覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,getNullableResult为查询时 mysql的字符串类型转换成 java的Type类型的方法
③在MyBatis核心配置文件中进行注册
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`password` int(11) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`birthday` bigint(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.atguigugroupId>
<artifactId>day45mybatis-typeHandlersartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
dependencies>
project>
package com.atguigu.hander;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
/**
* BaseTypeHandler:表示基本的类型处理器
* :泛型,如果想转换哪个类型 就把泛型给它
*
* 注意:导入date包的时候 导入的是util包 不是sql包
*/
public class MyDateTypeHandler extends BaseTypeHandler<Date> {
/**
* 设置参数 保存数据 调用的是save方法
* @param ps 表示JDBC里面的预处理
* @param i 表示索引 日期的索引位置 在数据库里里面的字段在第4个
* @param date 表示日期
* @param jdbcType
* @throws SQLException
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Date date, JdbcType jdbcType) throws SQLException {
System.out.println("ps = " + ps); // ps = org.apache.ibatis.logging.jdbc.PreparedStatementLogger@4690b489
System.out.println("i = " + i); // i = 3
System.out.println("date = " + date); // date = Mon Nov 07 12:29:59 CST 2022
System.out.println("jdbcType = " + jdbcType); // jdbcType = null
// 获取当前时间
long time = date.getTime();
System.out.println("--------------------");
System.out.println(time);
// 第一个参数:表示索引的位置
// 第二个参数:表示日期的值
ps.setLong(i, time);
}
/**
* 获取结果集
* @param resultSet 表示结果集
* @param s 需要查询列的名字
* @return
* @throws SQLException
*/
@Override
public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
// 需要把数据库里面的数字 转换成日期
System.out.println("find ---> 1");
System.out.println("resultSet = " + resultSet); // resultSet = org.apache.ibatis.logging.jdbc.ResultSetLogger@67a20f67
System.out.println("s = " + s); // s = birthday
long aLong = resultSet.getLong(s);
Date date = new Date(aLong);
return date;
}
@Override
public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
System.out.println("find ---> 2");
return null;
}
@Override
public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
System.out.println("find ---> 3");
return null;
}
}
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties">properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<typeAliases>
<package name="com.atguigu.pojo"/>
typeAliases>
<typeHandlers>
<typeHandler handler="com.atguigu.hander.MyDateTypeHandler">typeHandler>
typeHandlers>
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
plugin>
plugins>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driver" value="com.mysql.cj.jdbc.Driver">property>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true">property>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/atguigu/dao/UserDao.xml">mapper>
mappers>
configuration>
package com.atguigu.pojo;
import java.util.Date;
public class User {
private int id;
private String username;
private String password;
private Date birthday;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday=" + birthday +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
定义UserDao接口
package com.atguigu.dao;
import com.atguigu.pojo.User;
import java.util.List;
public interface UserDao {
void save(User user);
User findUserById(Integer id);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.dao.UserDao">
<insert id="save" parameterType="user">
insert into user(username, password, birthday) values(#{username}, #{password}, #{birthday})
insert>
<select id="findUserById" parameterType="Integer" resultType="user">
select * from user where id=#{id}
select>
mapper>
package com.atguigu;
import com.atguigu.dao.UserDao;
import com.atguigu.pojo.User;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
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;
public class MybatisTest {
private UserDao userDao;
private SqlSession sqlSession;
private InputStream is;
@After
public void after() throws Exception{
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
is.close();
}
@Before
public void before() throws IOException {
// 1.需要找到核心配置文件
is = Resources.getResourceAsStream("sqlMapConfig.xml");
// 2.构建会话工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 3.读取核心配置文件里面的io流
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 4.获取会话对象
sqlSession = sqlSessionFactory.openSession();
// 5.通过会话工厂 获取userdao对象
userDao = sqlSession.getMapper(UserDao.class);
}
@Test
public void testSave(){
User user = new User();
user.setPassword("王五");
user.setPassword("123");
// 类型转换异常 因为pojo里面的日期类型 我们的数据库表里面是一个数据类型
user.setBirthday(new Date());
// 执行保存方法
userDao.save(user);
}
@Test
public void testFindUserById(){
User user = userDao.findUserById(10);
System.out.println(user); // User{id=10, username='null', password='123', birthday=Mon Nov 07 12:25:07 CST 2022}
}
}
MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤:
①导入通用PageHelper的坐标
②在mybatis核心配置文件中配置PageHelper插件
③测试分页数据获取
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>3.7.5version>
dependency>
<dependency>
<groupId>com.github.jsqlparsergroupId>
<artifactId>jsqlparserartifactId>
<version>0.9.1version>
dependency>
在sqlMapConfig.xml进行如下配置:
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
plugin>
plugins>
List<User> findAll();
<select id="findAll" resultType="User">
select * from user
select>
@Test
public void testFindAll(){
// 开始分页
// 第一个参数:表示 需要查询的是哪个页面
// 第二个参数:表示 每个页面显示几条数据
PageHelper.startPage(1, 2);
List<User> userList = userDao.findAll();
/*for (User user : userList) {
System.out.println("user = " + user);
}*/
PageInfo<User> pageInfo = new PageInfo<>(userList);
System.out.println("总记录数:" + pageInfo.getTotal()); // 总记录数:8
System.out.println("总页数:" + pageInfo.getPages()); // 总页数:4
System.out.println("是否是第一页:" + pageInfo.isIsFirstPage()); // 是否是第一页:true
System.out.println("是否是最后一页:" + pageInfo.isIsLastPage()); // 是否是最后一页:false
}
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

对应的sql语句:select * from orders o,user u where o.uid = u.id;
查询的结果如下:

需求:查询所有订单信息,关联查询下单用户信息
注意:
因为一个订单信息只能供某个用户使用,所以从查询订单信息出发关联查询用户信息为一对一查询。如
果从用户信息出发查询用户下的订单息则为一对多查询,因为一个用户可以有多个订单。
项目名字:mybatis-one2many
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
dependencies>
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` varchar(50) DEFAULT NULL,
`birthday` datetime default NULL COMMENT '生日',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES ('1', 'lucy', '123', '2018-12-12');
INSERT INTO `user` VALUES ('2', 'haohao', '123', '2019-12-12');
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ordertime` varchar(255) DEFAULT NULL,
`total` double DEFAULT NULL,
`uid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `orders` VALUES ('1', '2018-12-12', '3000', '1');
INSERT INTO `orders` VALUES ('2', '2018-12-12', '4000', '1');
INSERT INTO `orders` VALUES ('3', '2018-12-12', '5000', '2');
public class Order {
private int id;
private Date ordertime;
private double total;
//代表当前订单从属于哪一个客户
private int uid;
}
public class User {
private int id;
private String username;
private String password;
private Date birthday;
}
在resources目录下面新建mybatis的核心配置文件
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties">properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<typeAliases>
<package name="com.atguigu.pojo"/>
typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driver" value="com.mysql.cj.jdbc.Driver">property>
<property name="url" value="jdbc:mysql:///mybatis2?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true">property>
dataSource>
environment>
environments>
<mappers>
<package name="com.atguigu.dao"/>
mappers>
configuration>
package com.atguigu.dao;
import com.atguigu.pojo.Orders;
import java.util.List;
public interface OrdersDao {
/**
* 查询所有订单,并且把订单对应出来的所有用户给查询出来
* @return
*/
List<Orders> findAll();
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.dao.OrderDao">
<select id="findAll" resultType="order">
select * from orders
select>
mapper>
package com.atguigu;
import com.atguigu.dao.OrdersDao;
import com.atguigu.pojo.Orders;
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.InputStream;
import java.util.List;
public class MybatisTest {
// ctrl + alt + f :抽取成员变量
private SqlSession sqlSession;
private InputStream is;
private OrdersDao ordersDao;
/**
* 结束最后执行
*/
@After
public void after() throws Exception{
//提交事务
sqlSession.commit();
//6.释放资源
sqlSession.close();
is.close();
}
/**
* 开始
*/
@Before
public void before() throws Exception{
//
// 1 需要找到核心配置文件
// ctrl + p : 表示查看参数
is = Resources.getResourceAsStream("sqlMapConfig.xml");
// 2 构建会话工厂
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 3 读取核心配置文件里面的io流
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
// 4 获取会话对象
sqlSession = sqlSessionFactory.openSession();
// 5 通过会话工厂,获取userdao对象
ordersDao = sqlSession.getMapper(OrdersDao.class);
}
@Test
public void testFindOrderAll(){
List<Orders> ordersList = ordersDao.findAll();
for (Orders orders : ordersList) {
System.out.println(orders);
}
}
}

使用resultMap,定义专门的resultMap用于映射一对一查询结果
修改Order类
在Order类中加入User类的对象作为Order类的一个属性

重新定义OrderDao.xml文件
resultMap常用标签

<resultMap id="orderMap" type="Orders">
<id column="id" property="user.id">id>
<result column="username" property="user.username">result>
<result column="password" property="user.password">result>
<result column="birthday" property="user.birthday">result>
resultMap>
<select id="findAll" resultMap="orderMap">
select o.*,u.username,u.password,u.birthday from orders o, user u where o.uid = u.id;
select>
<resultMap id="orderMap" type="orders">
<id column="id" property="id">id>
<result column="ordertime" property="ordertime">result>
<result column="total" property="total">result>
<association property="user" javaType="user">
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
association>
resultMap>
<select id="findAll" resultMap="orderMap">
select o.*,u.username,u.password,u.birthday from orders o, user u where o.uid = u.id;
select>

用户表和订单表的关系为:一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

对应的sql语句:select * from user u , orders o where u.id=o.uid
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rn6uA1JM-1667820988079)(assets/image-20221107191124676.png)]
User类添加ordersList属性

package com.atguigu.dao;
import com.atguigu.pojo.User;
import java.util.List;
public interface UserDao {
List<User> findAll();
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.dao.UserDao">
<resultMap id="userMap" type="user">
<id column="id" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
<collection property="ordersList" ofType="orders">
<result column="id" property="id">result>
<result column="ordertime" property="ordertime">result>
<result column="total" property="total">result>
collection>
resultMap>
<select id="findAll" resultMap="userMap">
select * from user u, orders o where u.id = o.uid;
select>
mapper>
@Test
public void testFindUserAll(){
List<User> userList = userDao.findAll();
for (User user : userList) {
System.out.println(user);
}
}
