Mybatis的复习

  • 创建一个maven项目
  • 开发环境
    • maven依赖环境
  • 创建mysql数据库
  • 创建表
  • 插入数据
  • jdbc程序问题总结
    • 使用jdbc查询mysql数据库中用户表的记录
    • 测试程序
    • 问题总结
  • mybatis是什么
  • mybatis框架
  • mybatis环境搭建
    • 项目结构图
  • 日志的输出
  • 根据用户id(主键)查询用户信息
    • 创建po类
    • 映射文件
    • 在SqlMapConfig.xml加载映射文件
    • 程序编写
  • 根据用户名称模糊查询用户信息
    • 修改映射文件User.xml
    • 修改测试程序
    • 使用concat函数根据用户名称模糊查询用户信息
  • #{}和${}总结
  • selectOne和selectList的区别
  • 添加用户
    • 修改User.xml
    • 测试程序
    • 控制台输出
    • 新增用户返回新增用户的主键
      • mysql数据库中 自增主键返回
  • 删除用户
  • 更新用户
  • mybatis与hibernate的区别与应用
  • mybatis开发 Dao的方法
    • SqlSession使用范围
      • SqlSessionFactoryBuilder
      • SqlSessionFactory
      • SqlSession
    • 原始dao开发方法(程序员需要写dao接口和dao实现类)
      • dao接口
      • dao接口实现类
      • dao接口实现类测试
      • 原始Dao开发问题
  • Mapper动态代理方式
  • SqlMapConfig.xml
    • properties属性
  • settings全局参数配置
    • mybatis的settings全局参数配置
  • typeAliases(别名)
    • mybatis官网对typeAliases别名的介绍
    • 批量定义别名
  • typeHandlers(类型处理器)
    • mybatis官网typeHandlers的介绍
  • mappers(映射配置)
    • 通过resource加载单个映射文件
    • 通过mapper接口加载单个mapper
    • 批量加载mapper(推荐使用)
  • 输入映射
    • 需求
    • 定义包装类型pojo
  • 输出映射
    • resultType
    • 总结
  • resultMap
    • resultMap使用方法
      • 定义resultMap
  • 动态Sql
    • 需求
  • Sql片段
    • 定义sql片段
    • 使用sql片段
  • foreach
    • 需求
    • 在输入参数类型中添加List ids传入多个id
      • 另外一个sql的实现

创建一个maven项目

开发环境

java环境:jdk1.8
eclipse:
mysql

maven依赖环境

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.company</groupId><artifactId>mybatis</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><dependencies><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.4</version></dependency><!-- https://mvnrepository.com/artifact/log4j/log4j --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.19</version></dependency><!-- https://mvnrepository.com/artifact/junit/junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>
</project>

创建mysql数据库

//创建数据库
create database mybatis;

创建表

//创建用户表
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(32) NOT NULL COMMENT '用户名称',`birthday` date DEFAULT NULL COMMENT '生日',`sex` char(1) DEFAULT NULL COMMENT '性别',`address` varchar(256) DEFAULT NULL COMMENT '地址',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
//创建订单表
CREATE TABLE `orders` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NOT NULL COMMENT '下单用户id',`number` varchar(32) NOT NULL COMMENT '订单号',`createtime` datetime NOT NULL COMMENT '创建订单时间',`note` varchar(100) DEFAULT NULL COMMENT '备注',PRIMARY KEY (`id`),KEY `FK_orders_1` (`user_id`),CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
//创建商品表CREATE TABLE `items` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) NOT NULL COMMENT '商品名称',`price` float(10,1) NOT NULL COMMENT '商品定价',`detail` text COMMENT '商品描述',`pic` varchar(64) DEFAULT NULL COMMENT '商品图片',`createtime` datetime NOT NULL COMMENT '生产日期',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
//创建订单详细表
CREATE TABLE `orderdetail` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`orders_id` INT ( 11 ) NOT NULL COMMENT '订单id',
`items_id` INT ( 11 ) NOT NULL COMMENT '商品id',
`items_num` INT ( 11 ) DEFAULT NULL COMMENT '商品购买数量',
PRIMARY KEY ( `id` ),
KEY `FK_orderdetail_1` ( `orders_id` ),
KEY `FK_orderdetail_2` ( `items_id` ),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY ( `orders_id` ) REFERENCES `orders` ( `id` ) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY ( `items_id` ) REFERENCES `items` ( `id` ) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE = INNODB AUTO_INCREMENT = 5 DEFAULT CHARSET = utf8;

插入数据

INSERT INTO `user` ( `id`, `username`, `birthday`, `sex`, `address` )
VALUES( 1, '王五', NULL, '2', NULL ),( 10, '张三', '2014-07-10', '1', '北京市' ),( 16, '张小明', NULL, '1', '河南郑州' ),( 22, '陈小明', NULL, '1', '河南郑州' ),( 24, '张三丰', NULL, '1', '河南郑州' ),( 25, '陈小明', NULL, '1', '河南郑州' ),( 26, '王五', NULL, NULL, NULL );
INSERT INTO `items` ( `id`, `name`, `price`, `detail`, `pic`, `createtime` )
VALUES( 1, '台式机', 3000.0, '该电脑质量非常好!!!!', NULL, '2015-02-03 13:22:53' ),( 2, '笔记本', 6000.0, '笔记本性能好,质量好!!!!!', NULL, '2015-02-09 13:22:57' ),( 3, '背包', 200.0, '名牌背包,容量大质量好!!!!', NULL, '2015-02-06 13:23:02' );
INSERT INTO `orders` ( `id`, `user_id`, `number`, `createtime`, `note` )
VALUES( 3, 1, '1000010', '2015-02-04 13:22:35', NULL ),( 4, 1, '1000011', '2015-02-03 13:22:41', NULL ),( 5, 10, '1000012', '2015-02-12 16:13:23', NULL );
INSERT INTO `orderdetail` ( `id`, `orders_id`, `items_id`, `items_num` )
VALUES( 1, 3, 1, 1 ),( 2, 3, 2, 3 ),( 3, 4, 3, 4 ),( 4, 4, 2, 3 );

jdbc程序问题总结

使用jdbc查询mysql数据库中用户表的记录

pom依赖

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.company</groupId><artifactId>mybatis</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><dependencies><!-- mysql依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.18</version></dependency></dependencies>
</project>

测试程序

package test;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;/*** @author 86182* @date* @description: 通过单独的jdbc程序,总结其中的问题*/
public class TestCase {public static void main(String[] args) {// 数据库连接Connection connection = null;// 预编译的Statement,使用预编译的Statement提高数据库性能PreparedStatement preparedStatement = null;// 结果 集ResultSet resultset = null;try {// 加载数据库驱动Class.forName("com.mysql.cj.jdbc.Driver");// 通过驱动管理类获取数据库链接connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8&serverTimezone=Asia/Shanghai","root", "root");// 定义sql语句 ?表示占位符String sql = "select * from user where username=?";// 获取预处理statementpreparedStatement = connection.prepareStatement(sql);// 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值preparedStatement.setString(1, "王五");// 向数据库发出sql执行查询,查询出结果集resultset = preparedStatement.executeQuery();// 遍历查询结果集while (resultset.next()) {System.out.println(resultset.getString("id") + "  " + resultset.getString("username"));}} catch (Exception e) {e.printStackTrace();} finally {//释放资源if(resultset!=null){try {resultset.close();} catch (SQLException e) {e.printStackTrace();}}if(preparedStatement!=null){try {preparedStatement.close();} catch (SQLException e) {e.printStackTrace();}}if(connection!=null){try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

测试结果

问题总结

1、数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。
设想:使用数据库连接池管理数据库连接
2、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护
将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。
3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护
将sql语句及占位符号和参数全部配置在xml中
4、从resutSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护
将查询的结果集,自动映射成java对象

mybatis是什么

mybatis是一个持久层的框架,是apache下的顶级项目。
mybatis托管到goole code下,再后来托管到github
mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,
自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。
可以将向 preparedStatement中的输入参数自动进行输入映射
将查询结果集灵活映射成java对象。(输出映射)

mybatis框架

1、mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、>一个是缓存执行器。
5、Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。>mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过>Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对>preparedStatement设置参数。
7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过>Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

mybatis环境搭建

mybatis运行环境(jar包):
从https://github.com/mybatis/mybatis-3/releases下载,3.5.4版本
mybatis的jar下载地址
lib下:依赖包
mybatis-3.5.4.jar:核心 包
mybatis-3.5.4.pdf,操作指南
加入mysql的驱动包
mysql的驱动包下载地址
日志的jar包下载地址
log4j的jar下载地址

项目结构图

日志的输出

# 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

根据用户id(主键)查询用户信息

创建po类

Po类作为mybatis进行sql映射使用,po类通常与数据库表对应

package cn.itcast.mybatis.po;import java.util.Date;public class User {//属性名和数据库表的字段对应private int id;private String username;// 用户姓名private Date birthday;// 生日private String sex;// 性别private String address;// 地址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 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;}public String toString() {return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address="+ address + "]";}
}

映射文件

映射文件命名:
User.xml(原始ibatis命名),mapper代理开发映射文件名称叫XXXMapper.xml,
比如:UserMapper.xml、 ItemsMapper.xml
在映射文件中配置sql语句。

<?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命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用
-->
<mapper namespace="cn.itcast.mybatis.po"><select id="findAll" resultType="cn.itcast.mybatis.po.User">select * from user</select><!-- 在 映射文件中配置很多sql语句 --><!-- 需求:通过id查询用户表的记录 --><!-- 通过 select执行数据库查询id:标识 映射文件中的 sql将sql语句封装到mappedStatement对象中,所以将id称为statement的idparameterType:指定输入 参数的类型,这里指定int型 #{}表示一个占位符号#{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。--><select id="findUserById" resultType="cn.itcast.mybatis.po.User" parameterType="int">select * from user where id=#{id}</select>
</mapper>

在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">
<configuration><!-- 加载属性文件 --><properties resource="db.properties"/><typeAliases><package name="cn.itcast.mybatis.po"/></typeAliases><!-- 和spring整合后environment配置将废除 --><environments default="development"><environment id="development"><!-- 使用jdbc事务管理,事务控制由mybatis --><transactionManager type="JDBC"/><!--数据库连接池 ,由mybatis管理 --><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></environment></environments><mappers><mapper resource="sqlmap/User.xml"/></mappers>
</configuration>

程序编写

package cn.itcast.mybatis.first;import java.io.IOException;
import java.io.InputStream;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.Test;import cn.itcast.mybatis.po.User;
/*** *@author 86182*@date 2020年2月27日上午12:11:32*@description:入门程序*/
public class MybatisFirst {//根据id查询用户信息,得到一条记录结果@Testpublic void findUserByIdTes() throws IOException {//mybatis的配置文件String resource="SqlMapConfig.xml";//得到配置文件流InputStream inputStream=Resources.getResourceAsStream(resource);//创建会话工厂,传入mybatis的配置文件信息SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);//通过工厂得到SqlSessionSqlSession ss=sf.openSession();//通过SqlSession操作数据库// 第一个参数:映射文件中statement的id,等于=namespace+"."+statement的id// 第二个参数:指定和映射文件中所匹配的parameterType类型的参数// sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象// selectOne查询出一条记录User user=ss.selectOne("findUserById",1);System.out.println(user.getUsername());ss.commit();//释放资源ss.close();}}

根据用户名称模糊查询用户信息

修改映射文件User.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命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用
-->
<mapper namespace="cn.itcast.mybatis.po"><select id="findAll" resultType="cn.itcast.mybatis.po.User">select * from user</select><!-- 在 映射文件中配置很多sql语句 --><!-- 需求:通过id查询用户表的记录 --><!-- 通过 select执行数据库查询id:标识 映射文件中的 sql将sql语句封装到mappedStatement对象中,所以将id称为statement的idparameterType:指定输入 参数的类型,这里指定int型 #{}表示一个占位符号#{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。--><select id="findUserById" resultType="cn.itcast.mybatis.po.User" parameterType="int">select * from user where id=#{id}</select><!-- 根据用户名称模糊查询用户信息,可能返回多条resultType:指定就是单条记录所映射的java对象 类型${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。使用${}拼接sql,引起 sql注入${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value--><select id="findUserByName" resultType="cn.itcast.mybatis.po.User" parameterType="java.lang.String">select * from user where username like '%${username}%'</select>
</mapper>

修改测试程序

使用concat函数根据用户名称模糊查询用户信息

修改映射文件User.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="cn.itcast.mybatis.po"><select id="findUserByName2" resultType="cn.itcast.mybatis.po.User" parameterType="java.lang.String">select * from user where username like concat('%',#{username},'%')</select>
</mapper>

测试程序

@Testpublic void findUserByName2Test() throws IOException{String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);SqlSession ss=sf.openSession();List<User> user=ss.selectList("findUserByName2", "王五");for (User u : user) {System.out.println(u.getId()+"——————"+u.getSex());}ss.commit();ss.close();}

控制台输出结果

#{}和${}总结

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类
型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简>单类型值,#{}括号中可以是value或其它名称。
表示拼接sql串,通过{}表示拼接sql串,通过表示拼接sql串,通过{}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, 可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{}可以接 收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{}括号中只能是value。
会引起sql注入,所以不建议使用

selectOne和selectList的区别

selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

selectList可以查询一条或多条记录。

添加用户

修改User.xml

在User.xml中添加如下代码

<!-- 添加用户,parameterType:指定输入参数类型是pojo(包括用户信息)#{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值 --><insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">insert into user (id,username,birthday,sex,address) values(null,#{username},#{birthday},#{sex},#{address})</insert>

测试程序

@Testpublic void insertUser() throws IOException {String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);SqlSession ss=sf.openSession();User user=new User();user.setUsername("Alice");user.setSex("1");user.setBirthday(new Date());user.setAddress("北京房山区");ss.insert("insertUser", user);ss.commit();ss.close();}

控制台输出

新增用户返回新增用户的主键

mysql数据库中 自增主键返回

  1. 第一种方式

修改User.xml
在Insert插入语句中增加useGeneratedKeys=true,
keyProperty=“id”

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" useGeneratedKeys="true" keyProperty="id">insert into user (id,username,birthday,sex,address) values(null,#{username},#{birthday},#{sex},#{address})</insert>

测试程序

@Testpublic void insertUser() throws IOException {String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);SqlSession ss=sf.openSession();User user=new User();user.setUsername("Halen");user.setSex("1");user.setBirthday(new Date());user.setAddress("北京房山区");ss.insert("insertUser", user);//获取新增数据的key(主键)System.out.println(user.getId());System.out.println(user);ss.commit();ss.close();}

控制台输出

2. 第二种方式

mysql自增主键,执行insert提交之前自动生成一个自增主键
通过mysql函数获取到刚插入记录的自增主键
LAST_INSERT_ID()
是在insert之后调用LAST_INSERT_ID()函数查询自增主键

通过修改sql映射文件,可以将mysql自增主键返回:

<!-- 添加用户,parameterType:指定输入参数类型是pojo(包括用户信息)#{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值 --><insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" ><!--将插入数据的主键返回,返回到user对象中SELECT LAST_INSERT_ID():得到刚insert进去记录的主键值,只适用于自增主键keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序resultType:指定SELECT LAST_INSERT_ID()的结果类型没有resultType="java.lang.Integer"报 org.apache.ibatis.exceptions.PersistenceException: Error updating database.  Cause: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'cn.itcast.mybatis.po.insertUser!selectKey'.  It's likely that neither a Result Type nor a Result Map was specified.--><selectKey order="AFTER" keyProperty="id" resultType="java.lang.Integer">SELECT LAST_INSERT_ID()</selectKey>insert into user (id,username,birthday,sex,address) values(null,#{username},#{birthday},#{sex},#{address})</insert>

删除用户

User.xml中添加如下代码

<!--  删除用户-->
<delete id="deleteUser" parameterType="int">delete from user where id=#{id}</delete>

测试程序

@Testpublic void deleteUserTest() throws IOException {String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);SqlSession ss=sf.openSession();ss.delete("deleteUser", 29);ss.commit();ss.close();}

执行结果如下

更新用户

User.xml中添加如下代码

<!-- 根据id 更新用户需要传入用户的id用户的更新信息parameterType:指定user对象,包括id和更新信息,id必须存在#{id}获取输入user对象中id属性值--><update id="updateUser" parameterType="cn.itcast.mybatis.po.User">update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}</update>

测试程序

@Testpublic void updateUserTest() throws IOException {String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);SqlSession ss=sf.openSession();User user=new User();user.setId(31);user.setBirthday(new Date());user.setAddress("湖北武汉");user.setSex("0");user.setUsername("张俊");ss.update("updateUser", user);ss.commit();ss.close();}

测试程序也可以如下写

@Testpublic void updateUser2Test() throws IOException {String resource="SqlMapConfig.xml";InputStream inputStream=Resources.getResourceAsStream(resource);SqlSessionFactory sf=new SqlSessionFactoryBuilder().build(inputStream);SqlSession ss=sf.openSession();User user=ss.selectOne("findUserById",31);user.setBirthday(new Date());user.setAddress("湖北武汉");user.setSex("0");user.setUsername("李四");ss.update("updateUser", user);ss.commit();ss.close();}

测试结果

mybatis与hibernate的区别与应用

hibernate:是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sql,sql语句自动生成了。
对sql语句进行优化、修改比较困难的
应用场景:
用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。
mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM
框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)
应用场景:
适用与需求变化较多的项目,比如:互联网项目
企业进行技术选型,以低成本 高回报作为技术选型的原则,根据项目组的技术力量进行选择。

mybatis开发 Dao的方法

SqlSession使用范围

SqlSessionFactoryBuilder

通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory
SqlSessionFactoryBuilder当成一个工具类使用即可
不需要使用单例模式管理SqlSessionFactoryBuilder
在需要创建SqlSessionFactoryBuilder时候,只需要new一次SqlSessionFactoryBuilder

SqlSessionFactory

通过SqlSessionFactory创建SqlSession,使用单例模式管理SqlSessionFactory
(工厂一旦创建,使用一个实例)
将mybatis和spring整合后,使用单例模式管理SqlSessionFactory

SqlSession

SqlSession是一个面向用户(程序员)的接口
SqlSession提供了很多操作数据库的方法:如selectOne(返回单个对象)、selectList(返回单个或多个对象)、
SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性

SqlSession最佳应用场合在方法体内,定义成局部变量使用

原始dao开发方法(程序员需要写dao接口和dao实现类)

程序员需要写dao接口和dao实现类
需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession

dao接口

package cn.itcast.mybatis.dao;import cn.itcast.mybatis.po.User;/*** * @author 86182* @version 1.0*/
public interface UserDao {// 根据id查询用户信息public User findUserById(int id) throws Exception;// 添加用户信息public void insertUser(User user) throws Exception;// 删除用户信息public void deleteUser(int id) throws Exception;
}

dao接口实现类

package cn.itcast.mybatis.dao;import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;import cn.itcast.mybatis.po.User;public class UserDaoImpl implements UserDao {//需要向dao实现类中注入SqlSessionFactory//通过构造方法注入private SqlSessionFactory sqlSessionFactory;public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory=sqlSessionFactory;}public User findUserById(int id) throws Exception {SqlSession sqlSession=sqlSessionFactory.openSession();User user= sqlSession.selectOne("findUserById",id);sqlSession.commit();//释放资源sqlSession.close();return user;}public void insertUser(User user) throws Exception {SqlSession sqlSession=sqlSessionFactory.openSession();//执行插入操作sqlSession.insert("insertUser",user);//提交事务sqlSession.commit();//释放资源sqlSession.close();}public void deleteUser(int id) throws Exception {SqlSession sqlSession=sqlSessionFactory.openSession();//执行插入操作sqlSession.delete("deleteUser",id);//提交事务sqlSession.commit();//释放资源sqlSession.close();}}

dao接口实现类测试

package cn.itcast.mybatis.dao;import java.io.InputStream;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;import cn.itcast.mybatis.po.User;public class UserDaoImplTest {private SqlSessionFactory sqlSessionFactory;@Beforepublic void setUp() throws Exception {//mybatis配置文件String resource="SqlMapConfig.xml";//得到配置文件流InputStream  inputStream=Resources.getResourceAsStream(resource);//创建会话工厂,传入mybatis配置文件信息sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testFindUserById() throws Exception {//      fail("Not yet implemented");//创建UserDaoUserDao userDao=new UserDaoImpl(sqlSessionFactory);//调用UserDaoUser user=userDao.findUserById(1);System.out.println(user);}}

程序输入结果

原始Dao开发问题

1、dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。
2、 调用sqlsession方法时将statement的id硬编码了
3、调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

Mapper动态代理方式

程序员还需要编写mapper.xml映射文件
程序员编写mapper接口需要遵循一些开发规范,mybatis可以自己生成mapper接口实现类代理对象

开发规范:

  1. 在mapper.xml中namespace等于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">
<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用
-->
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
</mapper>
  1. mapper.java接口中的方法名和mapper.xml中statement的id一致
  2. mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致
  3. mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。


    修改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命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用
-->
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper"><select id="findUserById" resultType="User" parameterType="int">select * from user where id=#{id}</select><select id="findUserByName" resultType="User" parameterType="java.lang.String">select * from user where username like concat('%',#{username},'%')</select><select id="findAllUsers" resultType="User">select * from user</select><insert id="insertUser" parameterType="User">insert into user values (null,#{username},#{birthday},#{sex},#{address})</insert><update id="updateUser" parameterType="User">update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}</update><delete id="deleteUser" parameterType="int">delete from user where id=#{id}</delete>
</mapper>

在SqlMapConfig.xml中引用UserMapper.xml

修改UserMapper

测试程序

package cn.itcast.mybatis.mapper;import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;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 cn.itcast.mybatis.po.User;public class UserMapperTest {SqlSessionFactory sf;SqlSession ss;@Beforepublic void setUp() throws IOException {String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sf = new SqlSessionFactoryBuilder().build(inputStream);ss = sf.openSession();}@Afterpublic void after() {ss.commit();ss.close();}/*** * 查询所有的用户信息* * @throws Exception*/@Testpublic void testFindAllUsers() throws Exception {//创建UserMapper对象,mybatis自动生成mapper代理对象UserMapper mapper = ss.getMapper(UserMapper.class);List<User> users = mapper.findAllUsers();for (User user : users) {System.out.println(user);}}/*** * 根据id查询用户信息* * @throws Exception*/@Testpublic void testFindUserById() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);User user = mapper.findUserById(27);System.out.println(user);}/*** 根据用户名查询用户列表* * @throws Exception*/@Testpublic void testFindUserByName() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);List<User> users = mapper.findUserByName("明");for (User user : users) {System.out.println(user);}}/*** 添加用户信息* * @throws Exception*/@Testpublic void testInsertUser() throws Exception {User user = new User();user.setBirthday(new Date());user.setAddress("安徽黄山");user.setSex("1");user.setUsername("张筱雨");UserMapper mapper = ss.getMapper(UserMapper.class);mapper.insertUser(user);}/*** 更新用户信息* @throws Exception*/@Testpublic void testUpdateUser() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);List<User> user = mapper.findUserByName("张筱雨");for (User user2 : user) {user2.setUsername("张晓雨");mapper.updateUser(user2);}}/*** 删除用户信息* @throws Exception*/@Testpublic void testDeleteUser()  throws Exception{UserMapper mapper=ss.getMapper(UserMapper.class);mapper.deleteUser(32);}
}

总结:

  • 如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库。
  • 如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。
  • 系统 框架中,dao层的代码是被业务层公用的
  • mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求

SqlMapConfig.xml

  • mybatis的全局配置文件SqlMapConfig.xml,配置内容如下:

properties属性

将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值
将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其它xml可以引用该db.properties。
db.properties文件配置如下:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

在SqlMapConfig.xml加载属性文件

MyBatis 将按照下面的顺序来加载属性:

  • 在 properties 元素体内定义的属性首先被读取
  • 然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
  • 最后读取parameterType传递的属性,它会覆盖已读取的同名属性
  • 不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中
  • 在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX
  • 通过parameterType传递的属性具有最高优先级,resource或 url 加载的属性次之,
  • 最低优先级的是 properties 元素体内定义的属性

settings全局参数配置

mybatis框架在运行时可以调整一些运行参数
例如:开启二级缓存、开启延迟加载
全局参数将会影响mybatis的运行行为

mybatis的settings全局参数配置

typeAliases(别名)

在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些
别名,在mapper.xml中通过别名定义,方便开发。

mybatis官网对typeAliases别名的介绍

自定义别名:

引用别名:

批量定义别名

typeHandlers(类型处理器)

mybatis中通过typeHandlers完成jdbc类型和java类型的转换。
通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义.

mybatis官网typeHandlers的介绍

mappers(映射配置)

通过resource加载单个映射文件

使用相对于类路径的资源

通过mapper接口加载单个mapper

使用mapper接口类路径


按照上边的规范,将mapper.java和mapper.xml放在一个目录 ,且同名。

批量加载mapper(推荐使用)

输入映射

通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型

需求

完成用户信息的综合查询,需要传入查询条件很复杂(可能包括用户信息、其它信息,比如商品、订单的)

定义包装类型pojo

针对上边需求,建议使用自定义的包装类型的pojo。
在包装类型的pojo中将复杂的查询条件包装进去。

用户的扩展类

package cn.itcast.mybatis.po;
/**** @author 86182* @description:* 用户的扩展类**/
public class UserCustom extends User{//可以扩展用户的信息
}

包装类

package cn.itcast.mybatis.po;
/*** * @author 86182*@Description:**包装类型*/
public class UserQueryVo {//在这里包装所需要的查询条件//用户查询条件private UserCustom userCustom ;public UserCustom getUserCustom() {return userCustom;}public void setUserCustom(UserCustom userCustom) {this.userCustom = userCustom;}//可以包装其他的查询条件、订单、商品}

修改UserMapper.xml,添加如下代码

<!--用户信息综合查询  #{UserCustom.sex}:取出pojo包装对象中性别值#{UserCustom.sexusername}:取出pojo包装对象中用户名--><select id="findUserList" parameterType="UserQueryVo" resultType="UserCustom">select * from user where user.sex=#{userCustom.sex} and user.username like CONCAT('%',#{userCustom.username},'%')</select>


修改UserMapper.java

测试程序

package cn.itcast.mybatis.mapper;import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;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 cn.itcast.mybatis.po.User;
import cn.itcast.mybatis.po.UserCustom;
import cn.itcast.mybatis.po.UserQueryVo;public class UserMapperTest {SqlSessionFactory sf;SqlSession ss;@Beforepublic void setUp() throws IOException {String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sf = new SqlSessionFactoryBuilder().build(inputStream);ss = sf.openSession();}@Afterpublic void after() {ss.commit();ss.close();}/*** * 查询所有的用户信息* * @throws Exception*/@Testpublic void testFindAllUsers() throws Exception {//创建UserMapper对象,mybatis自动生成mapper代理对象UserMapper mapper = ss.getMapper(UserMapper.class);List<User> users = mapper.findAllUsers();for (User user : users) {System.out.println(user);}}/*** * 根据id查询用户信息* * @throws Exception*/@Testpublic void testFindUserById() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);User user = mapper.findUserById(27);System.out.println(user);}/*** 根据用户名查询用户列表* * @throws Exception*/@Testpublic void testFindUserByName() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);List<User> users = mapper.findUserByName("明");for (User user : users) {System.out.println(user);}}/*** 添加用户信息* * @throws Exception*/@Testpublic void testInsertUser() throws Exception {User user = new User();user.setBirthday(new Date());user.setAddress("安徽黄山");user.setSex("1");user.setUsername("张筱雨");UserMapper mapper = ss.getMapper(UserMapper.class);mapper.insertUser(user);}/*** 更新用户信息* @throws Exception*/@Testpublic void testUpdateUser() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);List<User> user = mapper.findUserByName("张筱雨");for (User user2 : user) {user2.setUsername("张晓雨");mapper.updateUser(user2);}}/*** 删除用户信息* @throws Exception*/@Testpublic void testDeleteUser()  throws Exception{UserMapper mapper=ss.getMapper(UserMapper.class);mapper.deleteUser(32);}/*** 用户信息的综合查询* @throws Exception*/@Testpublic void testFindUserList() throws Exception {//创建UserMapper对象,mybatis自动生成mapper代理对象UserMapper mapper = ss.getMapper(UserMapper.class);//创建包装对象,设置查询条件UserQueryVo userQueryVo=new UserQueryVo();UserCustom userCustom=new UserCustom();userCustom.setSex("1");userCustom.setUsername("张");userQueryVo.setUserCustom(userCustom);//调用mapper的方法List<UserCustom> users = mapper.findUserList(userQueryVo);for (UserCustom user : users) {System.out.println(user);}}
}

输出映射

使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。

resultType

需求:
用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页。
修改UserMapper.xml

<!-- 用户信息综合查询总数parameterType:指定输入类型和findUserList一样resultType:输出结果类型-->
<select id="findUserListCount" resultType="int" parameterType="UserQueryVo">select count(*) from user where username=#{userCustom.username} and password=#{userCustom.password}</select>

UserMapper.java中添加如下代码

// 用户信息综合查询总数public int findUserListCount(UserQueryVo userQueryVo) throws Exception;

测试程序

package cn.mybatis.mapper;import java.io.IOException;
import java.io.InputStream;
import java.util.List;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 cn.mybatis.pojo.User;
import cn.mybatis.pojo.UserCustom;
import cn.mybatis.pojo.UserQueryVo;public class UserMapperTest {SqlSessionFactory sf;SqlSession ss;@Beforepublic void before() throws IOException {String resource = "SqlMapConfig.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sf = new SqlSessionFactoryBuilder().build(inputStream);ss = sf.openSession();}@Afterpublic void after() {ss.commit();ss.close();}/*** 增加用户* * @throws Exception*/@Testpublic void testInsertUser() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);User user = new User();user.setUsername("张翰");user.setPassword("1234");mapper.insertUser(user);System.out.println(user.getId());}/*** 删除用户* * @throws Exception*/@Testpublic void testDeleteUser() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);mapper.deleteUser(3);}/*** 修改用户信息* * @throws Exception*/@Testpublic void testUpdateUser() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);User user = mapper.findUserById(1);user.setUsername("张良");int count = mapper.updateUser(user);System.out.println(count);}/*** 查找所有的用户信息* * @throws Exception*/@Testpublic void testFindAllUsers() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);List<User> users = mapper.findAllUsers();for (User user : users) {System.out.println(user);}}/*** 根据id寻找用户信息* * @throws Exception*/@Testpublic void testFindUserById() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);User user = mapper.findUserById(1);System.out.println(user);}/*** 根据用户名模糊查询,查找相关用户信息* * @throws Exception*/@Testpublic void testFindUserByUserName() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);List<User> users = mapper.findUserByUserName("良");for (User user : users) {System.out.println(user);}}/*** 用户信息综合查询* * @throws Exception*/@Testpublic void testFindUserList() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);UserCustom userCustom = new UserCustom();userCustom.setPassword("123456");userCustom.setUsername("张良");UserQueryVo userQueryVo = new UserQueryVo();userQueryVo.setUserCustom(userCustom);List<UserCustom> userCustoms = mapper.findUserList(userQueryVo);for (UserCustom userCustom2 : userCustoms) {System.out.println(userCustom2.getId() + "-" + userCustom.getUsername() + "-" + userCustom.getPassword());}}/*** 用户信息综合查询* * @throws Exception*/@Testpublic void testFindUserListCount() throws Exception {UserMapper mapper = ss.getMapper(UserMapper.class);UserCustom userCustom = new UserCustom();userCustom.setPassword("123456");userCustom.setUsername("张良");UserQueryVo userQueryVo = new UserQueryVo();userQueryVo.setUserCustom(userCustom);int count = mapper.findUserListCount(userQueryVo);System.out.println(count);}
}

总结

1.查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射
2.不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。在mapper.java指定的方法返回值类型不一样:

  • 输出单个pojo对象,方法返回值是单个对象类型
// 根据id查找用户信息public User findUserById(int id) throws Exception;
  • 输出pojo对象list,方法返回值是List
// 根据用户名称查找用户信息public List<User> findUserByUserName(String username) throws Exception;

生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList (返回集合对象调用 ).

resultMap

mybatis中使用resultMap完成高级输出结果映射

resultMap使用方法

如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
1.定义resultMap
2.使用resultMap作为statement的输出映射类型

定义resultMap

在UserMapper.xml中添加如下代码:

<!-- 使用resultMap输出映射 --><!-- 定义resultMap将select id id_,username username_,password password_ from user和User类中的属性做一个映射关系type:resultMap最终映射的java对象类型,可以使用别名id:对resultMap的唯一标识--><resultMap type="User" id="userResultMap"><!-- id表示查询结果集唯一标识column:查询出来的列名property:type指定的pojo中的属性名最终resultMap对column和property做一个映射关系(对应关系)--><id column="id_" property="id"/><!--对普通列映射定义  --><result column="username_" property="username"/><result column="password_" property="password"/></resultMap><!--使用resultMap进行输出映射  resultMap:指定定义的resultMap的id如果这个resultMap在其他的mapper文件,前面需要加namespace--><select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">select id id_,username username_,password password_ from user</select>

在UserMapper.java中添加如下代码:

测试程序

总结:
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。

动态Sql

动态Sql:
mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装

需求

用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql。
对查询条件进行判断,如果输入参数不为空才进行查询条件拼接

UserMapper.xml中

<!--用户信息综合查询 #{userCustom.username}:取出pojo包装对象中的用户名#{userCustom.password}:取出pojo包装对象中的密码 -->
<select id="findUserListBySql" resultType="UserCustom"parameterType="UserQueryVo">select * from user<where><if test="userCustom!=null"><if test="userCustom.username!=null and userCustom.username!=''">and username like concat('%',#{userCustom.username},'%')</if><if test="userCustom.password!=null and userCustom.password!=''">and password=#{userCustom.password}</if></if></where></select>

UserMapper.java中添加如下代码:

// 用户信息综合查询public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;

测试程序与结果:

Sql片段

定义sql片段

上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段

在UserMapper.xml中添加如下代码:

<!-- 定义sql片段, id:sql片段的唯一标识 讲演:基于单表的定义sql片段,这样这个sql片段可重用性才高 sql片段不要包含where --><sql id="query_useer_where"><if test="userCustom!=null"><if test="userCustom.username!=null and userCustom.username!=''">and username like concat('%',#{userCustom.username},'%')</if><if test="userCustom.password!=null and userCustom.password!=''">and password=#{userCustom.password}</if></if></sql>

使用sql片段

在UserMapper.xml中继续添加如下代码:

 <!--用户信息综合查询 #{userCustom.username}:取出pojo包装对象中的用户名 #{userCustom.password}:取出pojo包装对象中的密码 --><select id="findUserListBySql" resultType="UserCustom"parameterType="UserQueryVo">select * from user<!-- where自动去掉条件中的第一个and --><where><!--引用Sql片段的id,如果 refid指定的id不在本UserMapper.xml中,前面需要加namespace --><include refid="query_useer_where"></include><!-- 在这里还要引用其他的sql片段 --></where></select>

修改UserMapper.java,添加如下代码

// 使用sql片段进行用户信息综合查询public List<UserCustom> findUserListBySql(UserQueryVo userQueryVo) throws Exception;

测试程序与结果

foreach

向sql传递数组或List,mybatis使用foreach解析

需求

在用户查询列表和查询总数的statement中增加多个id输入查询
sql语句如下:
两种方法:
select * from user where id=1 or id=2;
select * from user where id in(1,2);

在输入参数类型中添加List ids传入多个id

修改UserMapper.xml
在查询条件中,查询条件定义成一个sql片段,需要修改sql片段

<!--用户信息综合查询 #{userCustom.username}:取出pojo包装对象中的用户名 #{userCustom.password}:取出pojo包装对象中的密码 --><select id="findUserListBySql" resultType="UserCustom"parameterType="UserQueryVo">select * from user<!-- where自动去掉条件中的第一个and --><where><!--引用Sql片段的id,如果 refid指定的id不在本UserMapper.xml中,前面需要加namespace --><include refid="query_useer_where"></include><!-- 在这里还要引用其他的sql片段 --></where></select><!-- 定义sql片段, id:sql片段的唯一标识 讲演:基于单表的定义sql片段, 这样这个sql片段可重用性才高 sql片段不要包含where --><sql id="query_useer_where"><if test="userCustom!=null"><if test="userCustom.username!=null and userCustom.username!=''">and username like concat('%',#{userCustom.username},'%')</if><if test="userCustom.password!=null and userCustom.password!=''">and password=#{userCustom.password}</if><if test="ids!=null"><!-- 使用foreach遍历ids collection:指定输入对象中集合属性 item:每个遍历生成对象中open:开始遍历时拼接的串close:结束遍历时拼接的串separator:遍历的两个对象中需要拼接的串--><!-- 使用实现下边的sql拼接AND (id=1 OR id=10 OR id=16)--><foreach collection="ids" item="user_id" open="AND (" close=")" separator="OR"><!-- 每个遍历需要拼接的串 -->id=#{user_id}</foreach></if></if></sql>

修改UserQueryVo.java

测试程序与输出结果

另外一个sql的实现

<!--实现 and id in(1,2)  -->
<foreach collection="ids" item="user_id" open="AND id in(" close=")" separator=",">#{user_id}
</foreach>

Mybatis的复习(一)相关推荐

  1. Mybatis的复习

    https://segmentfault.com/a/1190000014161097?utm_source=feed-content#articleHeader15 我推荐Java3y的文章. 放上 ...

  2. 【项目实战】 图书信息管理系统(Maven,mybatis)(第一个自己独立完成的项目)

    一.实验目的 题目七 图书信息管理系统 1 功能描述 设计一个图书信息管理系统,使之具有新建图书信息.显示.插入.删除.查询和排序等功能. 2 具体设计要求 图书信息包括:图书编号.书名.作者名.出版 ...

  3. JAVA 150道笔试题知识点整理

    JAVA 笔试题 整理了几天才整理的题目,都是在笔试或者面试碰到的,好好理解消化下,对你会有帮助,祝你找工作顺利,收到满意的 offer . 1.Java 基础知识 1.1 Java SE 语法 &a ...

  4. 关于spring以及springIOC,看这一篇就够了,给你总结的清新脱俗

    Spring及IOC介绍 Spring简介 Rod Johnson,Spring Framework创始人,著名作者.很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然 ...

  5. 一文搞定Spring及IOC,给你总结的清新脱俗!

    Spring及IOC介绍 Spring简介 Rod Johnson,Spring Framework创始人,著名作者.很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然 ...

  6. Mybatis复习笔记:1

    关于模糊查找 模糊查找其实有两种基本操作(之前学的时候看的不太仔细,漏了-) 第一种 <select id="findByType" parameterType=" ...

  7. 复习下mybatis 中 useGeneratedKeys 和 keyProperty 含义

    今天突然碰到这个错误,让我复习下mybatis 中 useGeneratedKeys 和 keyProperty 含义 nested exception is org.apache.ibatis.ex ...

  8. mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数

    mybatis复习02,简单的增删改查 创建数据表 user_info 在项目中创建数据表对应的实体类 UserInfo.java 在pom.xml文件中引入依赖 创建核心配置文件mybatis-co ...

  9. MyBatis复习笔记6:MyBatis缓存机制

    MyBatis缓存机制 MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制.缓存可以极大的提升查询效率. MyBatis系统中默认定义了两级缓存. 一级缓存和二级缓存. 默认情 ...

最新文章

  1. 这份书单,给那些想学Hadoop大数据、人工智能的人
  2. 捡到银行卡套取密码取现1万多元,犯了信用卡诈骗罪被判7个月
  3. realme x2 深度测试打不开_realme 的产品到底是不是贴牌的?
  4. [设计模式]单例模式
  5. 霸权?Google 阻止我写 Web 浏览器
  6. 缓存在哪里_蚂蚁金服中间件(4轮题目):MVCC+缓存穿透+悲观锁+NIO+负载均衡等
  7. 守卫数据中心命门的胡桃夹子-特权账号管理平台
  8. 偏微分方程数值解---学习总结
  9. 地理信息系统(GIS)的发展历程
  10. ubuntu修改ssh端口_在Ubuntu上更改SSH欢迎横幅
  11. UFS详细介绍---终章
  12. 955 互联网公司白名单来了!这些公司月薪 20k,没有 996!福利榜国内大厂只有这家!...
  13. Google word/sheets 常见的使用:
  14. 谷歌百度脸书IBM,人工智能四巨头2014盘点
  15. 《嫌疑人X的献身》-东野圭吾
  16. ThinkPHP3.2/ThinkPHP5对比
  17. 铁路工程词汇-中英对照
  18. SQL WHERE AND OR
  19. 2022-2000-1978:世纪前后22年
  20. AD19全局替换网络标号

热门文章

  1. 使用电脑自带的建站工具实现手机观看电脑上的电影
  2. 上传照片视频的小程序
  3. Google之GUAVA学习
  4. lia人是什么意思_男友狗是什么意思 什么人可以被称为男友狗
  5. /etc/init.d目录和/etc/rc.local脚本
  6. 【刷题】20230318
  7. 水准网测量平差matlab_MATLAB在测量平差数据处理中的应用
  8. 似是而非,DTU、RTU和工业网关究竟有什么区别?
  9. python实战(二)模拟登陆两小无猜网
  10. 逻辑斯谛(Logistic)回归