bootstrap和application优先级,一篇文章让你瞬间知道Mybatis框架是如何使用的

 2023-09-25 阅读 32 评论 0

摘要:文章目录mybatis概述mybatis简介mybatis历史为什么要使用mybatis。mybatis的Hello 示例程序插入记录并返回主键selectKey 标签的使用注解@KeyMap的使用。mybatis的核心配置之propertiesmybatis的核心配置之settingsmybatis的核心配置之typeAliasesmybatis的核心配置之typ

文章目录

    • mybatis概述
      • mybatis简介
      • mybatis历史
      • 为什么要使用mybatis。
    • mybatis的Hello 示例程序
      • 插入记录并返回主键
      • selectKey 标签的使用
      • 注解@KeyMap的使用。
    • mybatis的核心配置之properties
    • mybatis的核心配置之settings
    • mybatis的核心配置之typeAliases
    • mybatis的核心配置之typeHandlers
    • mybatis的核心配置之environments
      • environment 标签说明
      • transactionManager 标签说明
      • dataSource 标签说明
    • mybatis的核心配置之databaseIdProvider
      • databaseId测试
    • mybatis的核心配置之Mapper ( 使用最多 )
    • 注解配置sql语句
    • mybatis的参数传递
      • 一个普通数据类型
      • 多个普通数据类型
      • @Param注解命名参数
      • 传递一个Map对象作为参数(使用极少)
      • 一个Pojo数据类型( pojo就是JavaBean )
      • 模糊查询
      • ${}的使用
      • MySQL的字符串拼接,concat函数实现。
    • 自定义结果集 resultMap标签
      • resultMap的作用。
      • 创建一对一数据库表
      • 创建实体对象
      • 一对一级联属性使用
      • association 标签 嵌套结果集映射配置
      • association 定义分步查询
      • 延迟加载
      • 多对一、一对多的使用示例
      • collection标签 一对多,立即加载
      • 一对多,赖加载
      • 多列传值(了解)
    • 动态SQL语句
      • if 语句
      • where 语句
      • trim语句
      • choose( when , otherwise )语句
      • set语句
      • foreach语句
      • sql片段
    • mybatis缓存
      • mybatis的一级缓存的示例
      • mybatis的二级缓存
      • 二级缓存的演示
      • 如何自定义二级缓存 ( 知道 )
    • 缓存的使用顺序说明:
    • mybatis 逆向工程
      • 准备数据库表

mybatis概述

mybatis简介

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。

bootstrap和application优先级,MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录.

mybatis历史

原是apache的一个开源项目iBatis, 2010年6月这个项目由apache software foundation 迁移到了google code,随着开发团队转投Google Code旗下,ibatis3.x正式更名为Mybatis ,代码于2013年11月迁移到Github(下载地址见后)。

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)

为什么要使用mybatis。

maven java、MyBatis是一个半自动化的持久化层框架。

jdbc编程—当我们使用jdbc持久化的时候,sql语句被硬编码到java代码中。这样耦合度太高。代码不易于维护。在实际项目开发中会经常添加sql或者修改sql,这样我们就只能到java代码中去修改。

Hibernate和JPA
长而又难又复杂SQL,对于Hibernate而言处理也不容易
内部自动生产的SQL,不容易做特殊优化。
基于全映射的全自动框架,javaBean存在大量字段时无法只映射部分字段。导致数据库性能下降。

对开发人员而言,核心sql还是需要自己优化
sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。
可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录。成为业务代码+底层数据库的媒介

mybatis的Hello 示例程序

  • 创建一个数据库和一个单表
drop database if exists mybatis;create database mybatis;use mybatis;
##############################################################################
################################### 单表 ######################################
##############################################################################
## 创建单表
create table t_user(`id` int primary key auto_increment,`last_name`	varchar(50),`sex` int
);insert into t_user(`last_name`,`sex`) values('wzg168',1);select * from t_user;
  • Mybatis程序示例:
    1 先编写数据库表对应的User对象
public class User {private Integer id;private String lastName;private Integer sex;

maven和java有什么区别。2 编写mybatis的核心配置文件 : mybatis-config.xml ( 放在src目录下 )

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- environments是配置数据库连接属性 --><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://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><!--我们说,mybatis是把sql语句配置到xml配置文件中告诉mbyatis到哪里去加载sql语句的配置文件<mappers><mapper resource="org/mybatis/example/BlogMapper.xml"/></mappers> -->
</configuration>

测试的代码:

package com.atguigu.test;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;public class MybatisHelloTest {@Testpublic void test() throws IOException {// 从 XML 中构建 SqlSessionFactory// 读取mybatis的核心配置文件InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");// 通过sqlSessionFactoryBuilder创建SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);System.out.println(sqlSessionFactory);}}

3 编写Mapper接口 ( DAO接口一样 )
JavaBean名    Mapper接口命名习惯( 不需要自己实现 )   Dao命名 ( 需要自己实现 )
User   UserMapper    UserDao
Book     BookMapper    BookDao

在 mybatis中我们需要为Mapper接口编写mapper接口的方法中执行的sql语句的配置文件.

好文章是什么让人什么、JavaBean名    Mapper接口名     sql配置文件名
User    UserMapper     UserMapper.xml
Book    BookMapper     BoookMapper.xml

Mapper.xml和Mapper接口一般都是放在同一个包下

Mapper接口:

public interface UserMapper {// mybatis的hello world ==>>> 要求我们查询数据库表t_user中id为1的记录public User queryUserById(Integer id);
}

Mapper.xml配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--要修改mapper和namespace名称空间属性值它的属性值必须是Mapper接口的全类名
-->
<mapper namespace="com.atguigu.mapper.UserMapper"><!--public User queryUserById(Integer id);select标签表示配置一个select查询语句id 属性值必须是方法名parameterType 属性配置方法的参数类型       int 表示 java.lang.Integer类型resultType  属性设置方法的返回值类型在mybatis中占位符要写成为: #{}--><select id="queryUserById" parameterType="int" resultType="com.atguigu.pojo.User">select `id`,`last_name` lastName, `sex` from t_user where id = #{id}</select>
</mapper>

maven框架、修改Mybatis-config.xml核心配置文件,加载sql的配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- environments是配置数据库连接属性 --><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://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><!--我们说,mybatis是把sql语句配置到xml配置文件中告诉mbyatis到哪里去加载sql语句的配置文件--><mappers><!--,去加载UserMapper.xml配置文件 --><mapper resource="com/atguigu/mapper/UserMapper.xml"/></mappers>
</configuration>

测试代码:

@Test
public void test2() throws IOException {// 创建SqlSessionFactory对象InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);// SqlSession相当于Jdbc中的Connection连接对象SqlSession session = sqlSessionFactory.openSession();try {// 获取UserMapper的实现类UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.queryUserById(1);System.out.println(user);} finally {session.close();}
}

给mybatis添加日记操作:
先添加日记的jar包
junit_4.12.jar
log4j-1.2.17.jar
mybatis-3.5.1.jar
mysql-connector-java-5.1.7-bin.jar
org.hamcrest.core_1.3.0.jar
在src目录下,配置日记功能的配置文件. log4j.properties

# 全局日志配置
log4j.rootLogger=DEBUG, stdout
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
  • Mapper接口的CRUD实现
    Mapper接口:
public interface UserMapper {// mybatis的hello world ==>>> 要求我们查询数据库表t_user中id为1的记录public User queryUserById(Integer id);public List<User> queryUsers();public int saveUser(User user);public int deleteUserById(Integer id);public int updateUserById(User user);
}

Mapper.xml配置文件 :

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--要修改mapper和namespace名称空间属性值它的属性值必须是Mapper接口的全类名
-->
<mapper namespace="com.atguigu.mapper.UserMapper"><!--public User queryUserById(Integer id);select标签表示配置一个select查询语句id 属性值必须是方法名parameterType 属性配置方法的参数类型       int 表示 java.lang.Integer类型resultType  属性设置方法的返回值类型在mybatis中占位符要写成为: #{}--><select id="queryUserById" resultType="com.atguigu.pojo.User">select `id`,`last_name` lastName, `sex` from t_user where id = #{id}</select><!--    public List<User> queryUsers();resultType 属性设置查询回来的结果每一行转换成为什么具体的类型
--><select id="queryUsers" resultType="com.atguigu.pojo.User">select `id`,`last_name` lastName, `sex` from t_user</select><!--    public int saveUser(User user);insert语句配insert标签update语句配update标签delete语句配delete标签select语句配select标签
--><insert id="saveUser" parameterType="com.atguigu.pojo.User">insert into t_user( `last_name`,`sex` ) values(#{lastName},#{sex})</insert><!--    public int deleteUserById(Integer id);--><delete id="deleteUserById" >delete from t_user where id = #{id}</delete><!--    public int updateUserById(User user);--><update id="updateUserById" parameterType="com.atguigu.pojo.User">updatet_userset`last_name` = #{lastName} ,`sex` = #{sex}whereid = #{id}</update>
</mapper>

Mapper接口测试

package com.atguigu.test;import com.atguigu.mapper.UserMapper;
import com.atguigu.pojo.User;
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.BeforeClass;
import org.junit.Test;import java.io.IOException;public class UserMapperTest {static SqlSessionFactory sqlSessionFactory;/*** @BeforeClass注解要标识在static的方法上,它会在测试方法执行之前执行,做一些初始化工作. <br/>* @BeforeClass 属于junit4测试类*/@BeforeClasspublic static void init() throws IOException {sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml") );}@Testpublic void queryUserById() {SqlSession sqlSession = sqlSessionFactory.openSession();try {UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.queryUserById(1);System.out.println(user);} finally {sqlSession.close();}}@Testpublic void queryUsers() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper mapper = session.getMapper(UserMapper.class);mapper.queryUsers().forEach(System.out::println);} finally {session.close();}}@Testpublic void saveUser() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper mapper = session.getMapper(UserMapper.class);int i = mapper.saveUser(new User(null, "ccccccc", 1));System.out.println(i);session.commit();//手动提交事务,否则事务就默认回滚} finally {session.close();}}@Testpublic void deleteUserById() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.deleteUserById(5);// 写操作,都需要手动提交事务session.commit();} finally {session.close();}}@Testpublic void updateUserById() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.updateUserById(new User(4,"oomm", 0));session.commit();} finally {session.close();}}
}

使用Mapper接口开发需要注意的四个点:
1 Mapper.xml配置文件的名称空间值必须是Mapper接口的全类名
2 Mapper.xml配置文件中的id值必须是Mapper接口的方法名
3 Mapper.xml配置文件文件中参数的类型parameterType必须和Mapper接口的参数类型一致( parameterType参数可选 )
4 Mapper.xml配置文件中返回值类型resultType必须和Mapper接口的返回值类型一致

插入记录并返回主键

一般在插入数据库数据的时候,经常需要把当前插入的生成的id主键值返回.

<!--    public int saveUser(User user);insert语句配insert标签update语句配update标签delete语句配delete标签select语句配select标签useGeneratedKeys="true" 使用数据库生成的主键值keyProperty="id"        将返回的主键值,注入到哪个属性中
--><insert id="saveUser" useGeneratedKeys="true" keyProperty="id" parameterType="com.atguigu.pojo.User">insert into t_user( `last_name`,`sex` ) values(#{lastName},#{sex})</insert>

selectKey 标签的使用

selectKey标签可以给当前执行的sql语句再配置另一个查询功能的sql.

<insert id="saveUser" parameterType="com.atguigu.pojo.User"><!--selectKey标签可以配置一个查询语句order设置selectkey中的查询语句的执行顺序AFTER   后执行Before  先执行keyProperty="id"        将返回的主键值,注入到哪个属性中resultType="int"        表示返回的数据是什么类型--><selectKey order="AFTER" keyProperty="id" resultType="int">select last_insert_id()</selectKey>insert into t_user( `last_name`,`sex` ) values(#{lastName},#{sex})
</insert>

注解@KeyMap的使用。

@KeyMap可以把查询回来的多条记录封装为Map.
map的键是: 就是我们指定的唯一值的列 ( 一般使用主键列 )
map的值是: 每行记录转换的对象

Mapper接口:

/*** 1 将查询回来每一行记录都封装为USer对象. <br>* 2 按照指定的列做为key保存查询到的数据,封装为Map <br/>* @return*/
@MapKey("id")
public Map<Integer,User>queryUserForMap();

Mapper.xml配置文件:

	<!--    /*** 1 将查询回来每一行记录都封装为USer对象. <br>* 2 按照指定的列做为key保存查询到的数据,封装为Map <br/>* @return*/@MapKey("id")public Map<Integer,User>queryUserForMap();--><select id="queryUserForMap" resultType="com.atguigu.pojo.User">select `id`,`last_name`, `sex` from t_user</select>

测试代码:

@Test
public void queryUserForMap() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);Map<Integer, User> map = userMapper.queryUserForMap();System.out.println( map.getClass() );for (Map.Entry<Integer, User>entry : map.entrySet()) {System.out.println( entry.getKey() + " = " +  entry.getValue());}} finally {session.close();}
}

mybatis的核心配置之properties

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--properties标签可以配置键值对这里的键值对可以供数据库环境使用.resource属性用来加载外部的jdbc.properties属性信息--><properties resource="jdbc.properties"><property name="username" value="root"/><property name="password" value="root"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="driverClassName" value="com.mysql.jdbc.Driver"/></properties><!-- environments是配置数据库连接属性 --><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--修改数据库的连接属性--><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--我们说,mybatis是把sql语句配置到xml配置文件中告诉mbyatis到哪里去加载sql语句的配置文件--><mappers><!--,去加载UserMapper.xml配置文件 --><mapper resource="com/atguigu/mapper/UserMapper.xml"/></mappers>
</configuration>

mybatis的核心配置之settings

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。下表描述了设置中各项的意图、默认值等。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

mybatis的核心配置之typeAliases

<!--配置别名-->
<typeAliases><!--typeAlias配置一个别名type是你的具体类型的全类名alias 是别名<typeAlias type="com.atguigu.pojo.User" alias="user" />--><!-- 通过配置包名的方式配置所有JavaBean的别名别名到底是啥,怎么用默认别名,就是类名,但一般用类名首字母小写居多--><package name="com.atguigu.pojo"/></typeAliases>

在这里插入图片描述

mybatis的核心配置之typeHandlers

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

mybatis的核心配置之environments

environments 标签用于配置数据库环境,
可以配置多个
SqlSessionFactory是单例的. 一个数据库对应一个SqlSessionFactory对象

environment 标签说明

environment 可以配置一个数据库环境
在这里插入图片描述

transactionManager 标签说明

在这里插入图片描述
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
• JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
• MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。

dataSource 标签说明

type 属性的值有三种: UNPOOLED 、 POOLED 、 JNDI。自定义(实现DataSourceFactory接口)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
• 大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形

mybatis的核心配置之databaseIdProvider

它可以提供多数据库的支持.

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。

	<databaseIdProvider type="DB_VENDOR"><property name="SQL Server" value="sqlserver" /><property name="MySQL" value="mysql" /><property name="DB2" value="db2" /><property name="Oracle" value="oracle" /></databaseIdProvider>

databaseId测试

<!--    public List<User> queryUsers();resultType 属性设置查询回来的结果每一笔转换成为什么具体的类型而不带有 databaseId 属性的它可以用于执行任何数据库
--><select id="queryUsers" resultType="user">select `id`,`last_name` lastName, `sex` from t_user</select><!--带有 databaseId 属性的是只是匹配了当前数据库就会执行的sql--><select id="queryUsers" resultType="user" databaseId="oracle">select `id`,`last_name` lastName, `sex` from t_user where 1 = 1</select>

mybatis的核心配置之Mapper ( 使用最多 )

<!--我们说,mybatis是把sql语句配置到xml配置文件中告诉mbyatis到哪里去加载sql语句的配置文件
-->
<mappers><!--,去加载UserMapper.xml配置文件 --><!--是指从ClassPath类路径下开始搜索配置文件<mapper resource="com/atguigu/mapper/UserMapper.xml"/> --><!--mapper表示配置搜索sql的配置文件class 表示搜索指定接口对应的配置文件注意事项:1 Mapper接口和Mapper.xml配置文件,必须在同一个包下2 Mapper接口文件名和Mapper.xml文件名要一致<mapper class="com.atguigu.mapper.UserMapper" />--><!--配置按照指定的包名去搜索所有Mapper.xml配置文件--><package name="com.atguigu.mapper"/></mappers>

注解配置sql语句

编写一个模块,使用注解去配置方法的sql语句
UserMapper接口:

public interface UserMapper {/***  @Insert 配置 insert的sql语句 <br/>*  @SelectKey 配置一个查询语句( 主要用于配置一个Select语句,用于查询主键 ) <br>*          statement 配置你的sql语句 <br>*          before 配置是否是先执行selectKey中语句 <br/>*          keyProperty 配置查询回来的Key主键给哪个属性赋值 <br/>*          resultType 属性配置返回的主键数据类型* @param user* @return*/@SelectKey(statement = "select last_insert_id()",before = false, keyProperty = "id",resultType = Integer.class)@Insert("insert into t_user(`last_name`,`sex`) values(#{lastName},#{sex})")public int saveUser(User user);/*** @Update 配置 update语句* @param user* @return*/@Update("update t_user set `last_name` = #{lastName} , `sex` = #{sex} where id = #{id}")public int updateUserById(User user);/*** @Delete 注解 配置 delete 语句* @param id* @return*/@Delete("delete from t_user where id = #{id}")public int deleteUserById(Integer id);/***@Select 注解配置 select语句* @param id* @return*/@Select("select `id`, `last_name` lastName,`sex` from t_user where id = #{id}")public User queryUserById(Integer id);/*** @Select 注解配置 select语句* @return**/@Select("select `id`, `last_name` lastName,`sex` from t_user")public List<User> queryUsers();}

测试的代码:

public class UserMapperTest {/*** sqlSessionFactory是单例的. 一个数据库只有一个SqlSessionFactory对象实例*/static SqlSessionFactory sqlSessionFactory;@BeforeClasspublic static void init() throws Exception{sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));}@Testpublic void saveUser() {SqlSession session = sqlSessionFactory.openSession();try {// 获取UserMapper实现类UserMapper userMapper = session.getMapper(UserMapper.class);User user = new User(null,"ddee" , 1);System.out.println(userMapper.saveUser(user));System.out.println(user);session.commit();} finally {session.close();}}@Testpublic void updateUserById() {SqlSession session = sqlSessionFactory.openSession();try {// 获取UserMapper实现类UserMapper userMapper = session.getMapper(UserMapper.class);User user = new User(7,"bbj" , 0);userMapper.updateUserById(user);session.commit();} finally {session.close();}}@Testpublic void deleteUserById() {SqlSession session = sqlSessionFactory.openSession();try {// 获取UserMapper实现类UserMapper userMapper = session.getMapper(UserMapper.class);User user = new User(7,"bbj" , 0);userMapper.deleteUserById(8);session.commit();} finally {session.close();}}@Testpublic void queryUserById() {SqlSession session = sqlSessionFactory.openSession();try {// 获取UserMapper实现类UserMapper userMapper = session.getMapper(UserMapper.class);System.out.println(userMapper.queryUserById(9));} finally {session.close();}}@Testpublic void queryUsers() {SqlSession session = sqlSessionFactory.openSession();try {// 获取UserMapper实现类UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.queryUsers().forEach(System.out::println);} finally {session.close();}}
}

数据库中的自增是不回滚的。
注解方式和xml方式可以共用,但不能同时写。一般来说,简单的SQL语句使用注解方式,复杂的SQL语句使用xml方式。

mybatis的参数传递

参数传递是指如何将mapper接口方法中的参数传递给sql语句的占位符. 简单点说,就是 #{} 里应该写啥

一个普通数据类型

Mapper接口:

public interface UserMapper {public User queryUserById(Integer id) ;
}

Mapper.xml配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace名称空间的值要改为对应的Mapper接口的全类名
-->
<mapper namespace="com.atguigu.mapper.UserMapper"><!--    public User queryUserById(Integer id);当Mapper接口参数是一个普通类型的时候,#{}中可以写任意的内容,只是推荐写成为参数名.为了更好的可读性--><select id="queryUserById" resultType="com.atguigu.pojo.User">select `id`,`last_name` lastName,`sex` from t_user where id = #{id}</select>
</mapper>

测试代码:

public class UserMapperTest {static SqlSessionFactory sqlSessionFactory;@BeforeClasspublic static void init() throws Exception{sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));}@Testpublic void queryUserById() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.queryUserById(1);System.out.println(user);} finally {session.close();}}
}

多个普通数据类型

Mapper接口:

/*** 根据给定的性别和名称查询用户信息 <br/>** @Param("name") String name 表示将第一个参数的参数名设置为name.** @return*/
public List<User> queryUsersBySexOrName(String name, Integer sex);

Mapper.xml配置文件:

<!--    /*** 根据给定的性别和名称查询用户信息* @return*/public List<User> queryUsersBySexOrName(String name,Integer sex);resultType属性是指定查询回来的每一行数据转换的具体的类型,在传递的参数是多个普通类型的情况下.有两种方案可以传递参数的值到占位符中.第一种情况是: (mybatis3.5支持)(mybatis3.4是用0,1来表示的)arg0    表示第一个参数arg1    表示第二个参数......以此类推argN    表示第N+1个参数第二种情况是:(推荐使用)param1  表示第一个参数param2  表示第二个参数......以此类推paramN  表示第n个参数--><select id="queryUsersBySexOrName" resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_userwhere`last_name` = #{param1} or `sex` = #{param2}</select>

测试的代码:

@Test
public void queryUsersBySexOrName(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.queryUsersBySexOrName("ccccccc", 1).forEach(System.out::println);} finally {session.close();}
}

@Param注解命名参数

Mapper接口:

/*** 根据给定的性别和名称查询用户信息 <br/>** @Param("name") String name 表示将第一个参数的参数名设置为name.** @return*/
public List<User> queryUsersBySexOrName(@Param("name") String name, @Param("sex") Integer sex);

Mapper.xml配置文件:

<!--   public List<User> queryUsersBySexOrName(@Param("name") String name, @Param("sex") Integer sex);如果我们在参数中使用了注解@Param("name") String name,则参数name的值可以通过注解指定的名称来进行传递也就是如下:@Param("name") String name           =====>>>>>      #{ name }@Param("sex") Integer sex            =====>>>>>      #{ sex }....... 以此类推@Param("xxxx") Integer sex           =====>>>>>      #{ xxxx }--><select id="queryUsersBySexOrName" resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_userwhere`last_name` = #{name} or `sex` = #{sex}</select>

传递一个Map对象作为参数(使用极少)

Mapper接口

/*** 按照map中给定的name和sex来进行查询用户信息* @param paramMap* @return*/
public List<User> queryUsersByMap(Map<String,Object> paramMap);

Mapper.xml配置文件:

<!--    /*** 按照map中给定的name和sex来进行查询用户信息* @param paramMap* @return*/public List<User> queryUsersByMap(Map<String,Object> paramMap);如果传递的参数是Map类型,则在#{}中需要写上map的key值表示传递相应key的值到sql的占位符中.示例代码:UserMapper userMapper = session.getMapper(UserMapper.class);Map<String,Object> map = new HashMap<>();map.put("name","ccccccc");map.put("sex",1);userMapper.queryUsersByMap(map).forEach(System.out::println);使用如下:Map<String,Object> map = new HashMap<>();map.put("name","ccccccc");      ====>>>>  #{ name }map.put("sex",1);               ====>>>>  #{ sex }--><select id="queryUsersByMap" resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_userwhere`last_name` = #{name} or `sex` = #{sex}</select>

测试的代码

@Test
public void queryUsersByMap(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);Map<String,Object> map = new HashMap<>();map.put("name","ccccccc");map.put("sex",1);userMapper.queryUsersByMap(map).forEach(System.out::println);} finally {session.close();}
}

一个Pojo数据类型( pojo就是JavaBean )

Mapper接口:

/*** 把 User 保存到数据库* @param user* @return*/
public int saveUser(User user);

Mapper.xml配置文件:

<!--    /*** 把 User 保存到数据库* @param user* @return*/public int saveUser(User user);如果参数是一个javaBean的时候,只需要在#{}占位符中写上对应数据库列的javaBean的属性名即可.public class User {private Integer id;private String lastName;    ====>>>  #{lastName}  表示传递 lastName 属性值给相应的占位符private Integer sex;        ====>>>  #{sex}  表示传递 sex 属性值给相应的占位符--><insert id="saveUser" parameterType="com.atguigu.pojo.User">insertinto t_user(`last_name`,`sex`)values (#{lastName},#{sex})</insert>

测试代码:

@Test
public void saveUser(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.saveUser(new User(null,"xxx", 1));session.commit();} finally {session.close();}
}

模糊查询

需求:现在要根据用户名查询用户对象。 也就是希望查询如下: select * from t_user where user_name like ‘%张%’

Mapper接口:

/*** 根据给定的name值做like模糊查询用户信息* @param name* @return*/
public List<User> queryUsersByNameLike(String name);

Mapper.xml配置文件:

<!--    /*** 根据给定的name值做like模糊查询用户信息* @param name* @return*/public List<User> queryUsersByNameLike(String name);--><select id="queryUsersByNameLike" resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_userwhere`last_name` like #{name}</select>

测试的代码:

@Test
public void queryUsersByNameLike() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);String name = "%xx%";userMapper.queryUsersByNameLike(name).forEach(System.out::println);} finally {session.close();}
}

${}的使用

在进行order by 排序的时候,不能使用#{},因为会带有双引号,#{}会考虑类型。只能用${},能使用#{}就使用#{}。

#{} 是占位符 , 所以不会有sql注入的问题
${} 是把参数内容原样输出 , 然后和原sql语句做字符串拼接操作. 会有sql注入的安全性问题

#{} 在一个参数的时候,可以任意写内容
${} 里只能写value, 或者使用@Param注解

#{} 一般用于给参数注入值
${} 一般用于表名

MySQL的字符串拼接,concat函数实现。

在这里插入图片描述
在Mapper.xml中的使用:

<!--    /*** 根据给定的name值做like模糊查询用户信息* @param name* @return*/public List<User> queryUsersByNameLike(String name);--><select id="queryUsersByNameLike" resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_userwhere`last_name` like concat('%',#{name},'%');</select>

自定义结果集 resultMap标签

resultMap标签可以对查询回来的结果集进行手动映射结果.
就是把查询回来的resultSet表中的数据如何指定哪个列赋值给JavaBean的哪个属性.

resultType 属性它可以指定一个JavaBean的具体类型.让查询回来的resultSet结果集自动映射上列名和属性名相同的属性.

在这里插入图片描述

resultMap的作用。

resultMap标签又叫自定义结果集标签.
resultMap标签经常使用在复杂的Bean对象上.并不会使用在简单的Bean对象上.

简单的Bean对象,是指JavaBean的属性中都是基本的数据类型.
复杂的Bean对象,是指属性的类型又是Bean对象 . 或者是集合的情况.

一般简单的Bean对象 ,都使用resultType属性使用自动映射结果集就可以实现功能效果了.
而复杂的JavaBean才会使用ResultMap标签来进行自定义结果集.

创建一对一数据库表

## 一对一数据表
## 创建锁表
create table t_lock(`id` int primary key auto_increment,`name` varchar(50)
);## 创建钥匙表
create table t_key(`id` int primary key auto_increment,`name` varchar(50),`lock_id` int ,foreign key(`lock_id`) references t_lock(`id`)
);## 插入初始化数据
insert into t_lock(`name`) values('阿里巴巴');
insert into t_lock(`name`) values('华为');
insert into t_lock(`name`) values('联想');insert into t_key(`name`,`lock_id`) values('马云',1);
insert into t_key(`name`,`lock_id`) values('任正非',2);
insert into t_key(`name`,`lock_id`) values('柳传志',3);

创建实体对象

public class Key {private Integer id;private String name;private Lock lock;public class Lock {private Integer id;private String name;

一对一级联属性使用

KeyMapper接口:

public interface KeyMapper {/*** 根据指定key的id值,一次性查询出key所有信息,以及key中lock的信息.* @param id* @return*/public Key queryKeyById(Integer id);
}

Mapper.xml配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace名称空间的值要改为对应的Mapper接口的全类名
-->
<mapper namespace="com.atguigu.mapper.KeyMapper"><!--resultMap自定义结果集id 唯一标识type 每一行转换的具体对象类型--><resultMap id="queryKeyByIdResultMap" type="com.atguigu.pojo.Key"><!--主键列映射--><id column="id" property="id" /><!--非主键列映射--><result column="name" property="name" /><!--级联属性映射级联  ===>>>> 一级一级关联--><result column="lock_id" property="lock.id" /><result column="lock_name" property="lock.name" /></resultMap>
<!--    /*** 根据指定key的id值,一次性查询出key所有信息,以及key中lock的信息.* @param id* @return*/public Key queryKeyById(Integer id);--><select id="queryKeyById" resultMap="queryKeyByIdResultMap">selectt_key.* ,t_lock.name lock_namefromt_key left join t_lockont_key.lock_id = t_lock.idwheret_key.id = #{id}</select>
</mapper>

测试的代码:

public class KeyMapperTest {static SqlSessionFactory sqlSessionFactory;@BeforeClasspublic static void init() throws Exception{sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));}@Testpublic void queryKeyById() {SqlSession session = sqlSessionFactory.openSession();try {KeyMapper keyMapper = session.getMapper(KeyMapper.class);System.out.println(keyMapper.queryKeyById(1));} finally {session.close();}}
}

association 标签 嵌套结果集映射配置

association 标签可以给Bean的子对象进行赋值映射操作.

<!--resultMap自定义结果集id 唯一标识type 每一行转换的具体对象类型--><resultMap id="queryKeyByIdResultMap" type="com.atguigu.pojo.Key"><!--主键列映射--><id column="id" property="id" /><!--非主键列映射--><result column="name" property="name" /><!--association标签可以配置子对象property 属性表示子对象名称javaType 表示子对象的全类名--><association property="lock" javaType="com.atguigu.pojo.Lock"><result column="lock_id" property="id" /><result column="lock_name" property="name" /></association></resultMap>
<!--    /*** 根据指定key的id值,一次性查询出key所有信息,以及key中lock的信息.* @param id* @return*/public Key queryKeyById(Integer id);--><select id="queryKeyById" resultMap="queryKeyByIdResultMap">selectt_key.* ,t_lock.name lock_namefromt_key left join t_lockont_key.lock_id = t_lock.idwheret_key.id = #{id}</select>

association 定义分步查询

association 标签还可以通过调用一个查询得到子对象.
LockMapper接口:

public interface LockMapper {/*** 简单查询lock表的信息( 不常用数据 )* @param id* @return*/public Lock queryLockByLockId(Integer id);
}

LockMapper.xml配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mapper.LockMapper"><!--    /*** 简单查询lock表的信息( 不常用数据 )* @param id* @return*/public Lock queryLockByLockId(Integer id);--><select id="queryLockByLockId" resultType="com.atguigu.pojo.Lock">select `id`,`name` from t_lock where id = #{id}</select>
</mapper>

KeyMapper接口:

/*** 要两步查询key的信息,一次只查key表的数据<br/>* @param keyId* @return*/
public Key queryKeyByKeyIdForTwoStep(Integer keyId);

KeyMapper.xml配置文件:

 <resultMap id="queryKeyByKeyIdForTwoStepResultMap" type="com.atguigu.pojo.Key"><id column="id" property="id" /><result column="name" property="name"/><!--需要调用association标签来调用一个查询从而得到子对象的数据property是子对象的属性名select 表示调用查询( 由名称空间+id组成 )column 属性把指定列的值传递给调用的方法做参数值--><association property="lock" column="lock_id"select="com.atguigu.mapper.LockMapper.queryLockByLockId"/></resultMap>
<!--    /*** 要两步查询key的信息,一次只查key表的数据<br/>* @param keyId* @return*/public Key queryKeyByKeyIdForTwoStep(Integer keyId);--><select id="queryKeyByKeyIdForTwoStep"resultMap="queryKeyByKeyIdForTwoStepResultMap">select `id`,`name`,`lock_id` from t_key where id = #{id}</select>

测试的代码:

@Test
public  void queryKeyByKeyIdForTwoStep(){SqlSession session = sqlSessionFactory.openSession();try {KeyMapper keyMapper = session.getMapper(KeyMapper.class);Key key = keyMapper.queryKeyByKeyIdForTwoStep(1);System.out.println(key);} finally {session.close();}
}

延迟加载

延迟加载在一定程序上可以减少很多没有必要的查询。给数据库服务器提升性能上的优化。
要启用延迟加载,需要在mybatis-config.xml配置文件中,添加如下两个全局的settings配置。

	   <!-- 打开延迟加载的开关 -->  <setting name="lazyLoadingEnabled" value="true" />  <!-- 将积极加载改为消极加载  按需加载 -->  <setting name="aggressiveLazyLoading" value="false"/>  

多对一、一对多的使用示例

  • 创建一对多数据库
## 一对多数据表
## 创建班级表
create table t_clazz(`id` int primary key auto_increment,`name` varchar(50)
);## 插入班级信息
insert into t_clazz(`name`) values('javaEE');
insert into t_clazz(`name`) values('C++');
insert into t_clazz(`name`) values('H5');
insert into t_clazz(`name`) values('LUA');## 创建学生表
create table t_student(`id` int primary key auto_increment,`name` varchar(50),`clazz_id` int,foreign key(`clazz_id`) references t_clazz(`id`)
);## 插入班级信息
insert into t_student(`name`,`clazz_id`) values('javaEE_1',1);
insert into t_student(`name`,`clazz_id`) values('javaEE_2',1);
insert into t_student(`name`,`clazz_id`) values('javaEE_3',1);
insert into t_student(`name`,`clazz_id`) values('C++_1',2);
insert into t_student(`name`,`clazz_id`) values('C++_2',2);
insert into t_student(`name`,`clazz_id`) values('H5_1',3);

collection标签 一对多,立即加载

public class Student {private Integer id;private String name;public class Clazz {private Integer id;private String name;private List<Student> stus;

Mapper接口:

public interface ClazzMapper {/*** 一次性查询出班级和此班级所有学生信息* @param clazzId 班级编号* @return*/public Clazz queryClazzByClazzIdForSimple(Integer clazzId);
}

mapper.xml配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mapper.ClazzMapper"><resultMap id="queryClazzByClazzIdForSimpleResultMap"type="com.atguigu.pojo.Clazz"><id column="id" property="id" /><result column="name" property="name" /><!--collection标签表示配置集合属性property 配置集合的名称ofType 配置集合中每个元素的具体类型--><collection property="stus" ofType="com.atguigu.pojo.Student"><!--对于集合,我们需要区分主键列和非主键列--><id column="stu_id" property="id" /><result column="stu_name" property="name" /></collection></resultMap>
<!--    /*** 一次性查询出班级和此班级所有学生信息* @param clazzId 班级编号* @return*/public Clazz queryClazzByClazzIdForSimple(Integer clazzId);--><select id="queryClazzByClazzIdForSimple"resultMap="queryClazzByClazzIdForSimpleResultMap">selectt_clazz.*,t_student.id stu_id,t_student.name stu_namefromt_clazz left join t_studentont_clazz.id = t_student.clazz_idwheret_clazz.id = #{clazzId}</select>
</mapper>

测试的代码:

package com.atguigu.mapper.test;import com.atguigu.mapper.ClazzMapper;
import com.atguigu.pojo.Clazz;
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.BeforeClass;
import org.junit.Test;import java.io.IOException;public class ClazzMapperTest {static SqlSessionFactory sqlSessionFactory;@BeforeClasspublic static void init() throws IOException {sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));}@Testpublic void queryClazzByClazzIdForSimple() {SqlSession session = sqlSessionFactory.openSession();try {// 获取班级Dao / mapperClazzMapper clazzMapper = session.getMapper(ClazzMapper.class);Clazz clazz = clazzMapper.queryClazzByClazzIdForSimple(1);System.out.println(clazz);} finally {session.close();}}
}

一对多,赖加载

分两次查,最后一次用的时候再查,不用不查.
StudentMapper接口:

public interface StudentMapper {/*** 根据班级编号查询学生信息* @param clazzId* @return*/public List<Student> queryStudentsByClazzId(Integer clazzId);
}

StudentMapper.xml配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mapper.StudentMapper">
<!--* 根据班级编号查询学生信息* @param clazzId* @return*/public List<Student> queryStudentsByClazzId(Integer clazzId);--><select id="queryStudentsByClazzId" resultType="com.atguigu.pojo.Student">select `id`,`name` from t_student where clazz_id = #{clazzId}</select>
</mapper>

ClazzMapper接口

/*** 根据班级编号查询班级信息, 分两次查,一次只查班级,一个查班级学生* @param clazzId* @return*/
public Clazz queryClazzByClazzIdForTwoStep(Integer clazzId);

ClazzMapper.xml配置文件

 <!--将查询回来的结果封装成为Clazz班级对象--><resultMap id="queryClazzByClazzIdForTwoStepResultMap"type="com.atguigu.pojo.Clazz"><id column="id" property="id" /><result column="name" property="name" /><!--collection标签可以把查询回来的数据封装成为集合,也可以通过调用一个查询得到集合property表示集合属性名称select 属性表示要调用哪个查询( 名称空间+id值 )column表示传递给调用方法的参数( 设置列名 )--><collection property="stus" column="id"select="com.atguigu.mapper.StudentMapper.queryStudentsByClazzId"/></resultMap>
<!--    /*** 根据班级编号查询班级信息, 分两次查,一次只查班级,一个查班级学生* @param clazzId* @return*/public Clazz queryClazzByClazzIdForTwoStep(Integer clazzId);--><select id="queryClazzByClazzIdForTwoStep"resultMap="queryClazzByClazzIdForTwoStepResultMap">select `id`,`name` from t_clazz where id = #{id}</select>

多列传值(了解)

多列传值是指在 association标签中或collection标签中调用的查询有多个参数如何传值.
在这里插入图片描述

动态SQL语句

动态的sql语句 ,是指mybatis通过在运行时动态的判断参数的值.从而改变sql的内容.叫动态sql.

准备工作:

public class User {private int id;private String lastName;private int sex;

if 语句

说明: if语句,可以动态的根据你的值来决定,是否需要动态的添加查询条件。

public interface UserMapper {/*** 根据User对象 name属性 和 sex属性进行查询用户 <br>* @param user* @return*/public List<User> queryUsersByUser(User user);
}

mapper.xml配置文件:

<select id="queryUsersByUser"parameterType="com.atguigu.pojo.User"resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_userwhere<!--if 判断.如果成立,就执行--><if test="lastName != null">last_name like concat('%',#{lastName},'%')</if><if test="sex == 1 or sex == 0">andsex = #{sex}</if>
</select>

测试代码:

@Test
public void queryUsersByUser() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.queryUsersByUser(new User(null, "xxx",10)).forEach(System.out::println);} finally {session.close();}
}

where 语句

说明: where语句,可以帮我们在多个动态语句中,有效的去掉前面的多余的and 或 or 之类的多余关键字

mapper.xml配置文件:

<select id="queryUsersByUser"parameterType="com.atguigu.pojo.User"resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_user<!--where标签可以去掉包含的内容前面的and 或 or关键字. 并且如果有内容还会添加where关键字--><where><!--if 判断.如果成立,就执行--><if test="lastName != null">last_name like concat('%',#{lastName},'%')</if><if test="sex == 1 or sex == 0">andsex = #{sex}</if></where>
</select>

测试的代码:

@Test
public void queryUsersByUser() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.queryUsersByUser(new User(null, null,10)).forEach(System.out::println);} finally {session.close();}
}

trim语句

说明: trim 可以动态在包含的语句前面和后面添加内容。也可以去掉前面或者后面给定的内容
prefix 前面添加内容
suffix 后面添加内容
suffixOverrides 去掉的后面内容
prefixOverrides 去掉的前面内容

<select id="queryUsersByUser"parameterType="com.atguigu.pojo.User"resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_user<!--trim 标签可以去掉包含内容前面 ,或 后面指定的内容.也可以在包含内容的前面 或 后面 添加指定的内容prefix 前面添加内容
suffix 后面添加内容
suffixOverrides 去掉的后面内容
prefixOverrides 去掉的前面内容--><trim suffixOverrides="and" prefixOverrides="and" prefix="where"><!--if 判断.如果成立,就执行--><if test="lastName != null">last_name like concat('%',#{lastName},'%') and</if><if test="sex == 1 or sex == 0">sex = #{sex}</if></trim>
</select>

choose( when , otherwise )语句

说明:choose when otherwise 可以执行多路选择判断,但是只会有一个分支会被执行。

Mapper接口:

public List queryUsersByUserChooseWhenOtherWise(User user);

mapper.xml配置文件:

<select id="queryUsersByUserChooseWhenOtherWise"parameterType="com.atguigu.pojo.User"resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_user<choose><when test="lastName != null">where last_name like concat('%',#{lastName},'%')</when><when test="sex == 0 or sex == 1">where sex = #{sex}</when><otherwise>where 1 = 1</otherwise></choose>
</select>

测试的代码:

@Test
public void queryUsersByUserChooseWhenOtherWise(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);List<User> users = userMapper.queryUsersByUserChooseWhenOtherWise(new User(null, null, 10));users.forEach(System.out::println);} finally {session.close();}
}

set语句

删除条件后的逗号 , 主要应用于 update 语句中

mapper.xml配置文件:

	<!--    public int updateUser(User user);--><update id="updateUser" parameterType="com.atguigu.pojo.User">updatet_user<!-- 可以去掉,包含内容后面的逗号,如果有包含的内容.还会添加set关键字 --><set>`last_name` = #{lastName} ,<if test="sex == 0 or sex == 1">`sex` = #{sex}</if></set>whereid = #{id}</update>

测试的代码:

@Test
public void updateUser(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);userMapper.updateUser(new User(16, "updated", 10));session.commit();} finally {session.close();}
}

foreach语句

foreach很直观就是遍历
一: 遍历查询条件
select * from 表名 where id in(xx,xx,xx)

Mapper接口:

//    一: 遍历查询条件
//    select * from 表名 where id in(xx,xx,xx)public List<User> queryUsersByIds(List<Integer> ids);

Mapper.xml配置文件:

<!--        //    一: 遍历查询条件//    select * from 表名 where id in(xx,xx,xx)public List<User> queryUsersByIds(List<Integer> ids);--><select id="queryUsersByIds" resultType="com.atguigu.pojo.User">select`id`,`last_name` lastName,`sex`fromt_user<!--collection 是遍历的数据源item 是遍历到的数据separator 遍历的每个元素中的间隔符open遍历前输出的内容close遍历后输出的内容--><foreach collection="list" item="id" separator="," open="where id in (" close=")">#{id}</foreach></select>

测试的代码:

@Test
public void queryUsersByIds(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);List<Integer> ids = new ArrayList<>();ids.add(1);ids.add(11);ids.add(12);List<User> users = userMapper.queryUsersByIds(ids);users.forEach(System.out::println);} finally {session.close();}
}

二:遍历批量插入
insert into 表名(列,列) values(?,?,?),(?,?,?)
Mapper接口

//    二:遍历批量插入
//    insert into 表名(列,列) values(?,?,?),(?,?,?)public int saveUsers(List<User> users);

mapper.xml配置文件:

<!--    //    二:遍历批量插入//    insert into 表名(列,列) values(?,?,?),(?,?,?)public int[] saveUsers(List<User> users);--><insert id="saveUsers">insert intot_user(`last_name`,`sex`)values<foreach collection="list" item="user" separator=",">(#{user.lastName},#{user.sex})</foreach></insert>

测试的代码:

@Test
public void saveUsers(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);List<User> users = new ArrayList<>();users.add(new User(null,"aaa", 1));users.add(new User(null,"bbb", 1));users.add(new User(null,"ccc", 1));userMapper.saveUsers(users);session.commit();} finally {session.close();}
}

sql片段

sql片段是我们抽取了多个sql语句中相同的公共部分的内容.用于统一维护的sql叫片段.
在这里插入图片描述

mybatis缓存

缓存: 缓存是指把经常访问的数据保存到高速缓冲区中.
缓存名词又可以理解为,保存中高速缓冲区中的数据.

常见的做法,就是把数据保存起来.方便快速访问.

一级缓存: 同一个sqlSession是一级缓存
二级缓存: 同一个SqlsessionFactory是二级缓存

mybatis的一级缓存的示例

在这里插入图片描述
测试的代码:

@Test
public void testFirstCache() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.queryUserById(1);System.out.println(user);User user1 = userMapper.queryUserById(1);System.out.println(user1);} finally {session.close();}
}
  • 一级缓存的管理
    缓存失效的四种情况:
    1.不在同一个SqlSession对象中
 @Testpublic void queryOne() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.queryUserById(1);System.out.println(user);} finally {session.close();}}
//    缓存失效的四种情况:
//            1.不在同一个SqlSession对象中@Testpublic void testFirstCacheFail1(){queryOne();queryOne();}

2.执行语句的参数不同。缓存中也不存在数据。

@Test
public void testFirstCacheFail2(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.queryUserById(1);System.out.println(user);User user1 = userMapper.queryUserById(2);System.out.println(user1);} finally {session.close();}
}

3.执行增,删,改,语句,会清空掉缓存

  //  3.执行增,删,改,语句,会清空掉缓存
@Test
public void testFirstCacheFail3(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.queryUserById(1);System.out.println(user);// 只要两次查询中,执行了写操作,,, insert,delete,update操作,缓存就会被清空userMapper.insertUser(new User(null,"abc", 1));User user1 = userMapper.queryUserById(1);System.out.println(user1);session.commit();} finally {session.close();}
}

4.手动清空缓存数据

//            4.手动清空缓存数据@Testpublic void testFirstCacheFail4(){SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.queryUserById(1);System.out.println(user);// clear 清空// cache缓存session.clearCache();User user1 = userMapper.queryUserById(1);System.out.println(user1);session.commit();} finally {session.close();}}

mybatis的二级缓存

二级缓存的图解示意
在这里插入图片描述
二级缓存的使用:
myBatis的二级缓存默认是不开启的。
1 我们需要在mybatis的核心配置文件中配置setting选项
在这里插入图片描述
2 在Mapper.xml的配置文件中加入cache标签。启动二级缓存
在这里插入图片描述
3 被二级缓存的对象必须要实现java的序列化接口。
在这里插入图片描述

二级缓存的演示

public void queryOne() {SqlSession session = sqlSessionFactory.openSession();try {UserMapper userMapper = session.getMapper(UserMapper.class);User user = userMapper.queryUserById(1);System.out.println(user);} finally {session.close();}
}@Test
public void testSecondCache(){queryOne();queryOne();
}

useCache="false"的演示和说明
useCache属性是在select标签中设置查询的结果是否缓存到二级缓存中.默认情况下它的值是true,表示保存到二级缓存中.
在这里插入图片描述
flushCache="false"的演示和说明
当执行insert / update / delete 这些语句的时候,都会清空缓存.
也可以通过在这些标签上使用属性 flushCache=“false” 设置不清空缓存.
在这里插入图片描述

如何自定义二级缓存 ( 知道 )

1 实现Mybatis中提供的Cache接口

public class MyCache implements Cache {private final String id;private Map<Object, Object> cache = new HashMap();public MyCache(String id) {this.id = id;}public String getId() {return this.id;}public int getSize() {return this.cache.size();}/*** 保存数据到二级缓存中* @param key* @param value*/public void putObject(Object key, Object value) {System.out.println("保存数据到二级缓存 key : " + key);System.out.println("保存数据到二级缓存 value : " + value);this.cache.put(key, value);}/*** 从二级缓存中取数据* @param key* @return*/public Object getObject(Object key) {System.out.println("从二级缓存中取数据 key : " + key);return this.cache.get(key);}public Object removeObject(Object key) {return this.cache.remove(key);}public void clear() {this.cache.clear();}public ReadWriteLock getReadWriteLock() {return null;}public boolean equals(Object o) {if (this.getId() == null) {throw new CacheException("Cache instances require an ID.");} else if (this == o) {return true;} else if (!(o instanceof Cache)) {return false;} else {Cache otherCache = (Cache)o;return this.getId().equals(otherCache.getId());}}public int hashCode() {if (this.getId() == null) {throw new CacheException("Cache instances require an ID.");} else {return this.getId().hashCode();}}
}

2 到Mapper.xml中去配置自定义的二级缓存.
在这里插入图片描述

缓存的使用顺序说明:

1、当我们执行一个查询语句的时候。mybatis会先去二级缓存中查询数据。
2 如果二级缓存中没有。就到一级缓存中取数据
3、如果二级缓存和一级缓存都没有。就发sql语句到数据库中去查询。
4、查询出来之后马上把数据保存到一级缓存中。
5、当SqlSession关闭的时候,会把一级缓存中的数据保存到二级缓存中。

mybatis 逆向工程

MyBatis逆向工程,简称MBG。是一个专门为MyBatis框架使用者定制的代码生成器。可以快速的根据表生成对应的映射文件,接口,以及Bean类对象。
逆向工程只能对单表生成CRUD操作

叫 mybatis-generator-core-1.3.2。

它可以帮我们对比数据库表之后,生成大量的这个基础代码。
这些基础代码有:
1、数据库表对应的javaBean对象
2、这些javaBean对象对应的Mapper接口
3、这些Mapper接口对应的配置文件

  	<!-- 去掉全部的注释 --><commentGenerator><property name="suppressAllComments" value="true" /></commentGenerator>

准备数据库表

create database mbg;use mbg;create table t_user(`id` int primary key auto_increment,`username` varchar(30) not null unique,`password` varchar(40) not null,`email` varchar(50)
);insert into t_user(`username`,`password`,`email`) values('admin','admin','admin@atguigu.com');
insert into t_user(`username`,`password`,`email`) values('wzg168','123456','admin@atguigu.com');
insert into t_user(`username`,`password`,`email`) values('admin168','123456','admin@atguigu.com');
insert into t_user(`username`,`password`,`email`) values('lisi','123456','admin@atguigu.com');
insert into t_user(`username`,`password`,`email`) values('wangwu','123456','admin@atguigu.com');create table t_book(`id` int primary key auto_increment,`name` varchar(50),`author` varchar(50),`price`	decimal(11,2),`sales`	int,`stock` int
);## 插入初始化测试数据
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
values(null , 'java从入门到放弃' , '国哥' , 80 , 9999 , 9);insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
values(null , '数据结构与算法' , '严敏君' , 78.5 , 6 , 13);insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
values(null , '怎样拐跑别人的媳妇' , '龙伍' , 68, 99999 , 52);insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
values(null , '木虚肉盖饭' , '小胖' , 16, 1000 , 50);insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
values(null , 'C++编程思想' , '刚哥' , 45.5 , 14 , 95);insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
values(null , '蛋炒饭' , '周星星' , 9.9, 12 , 53);insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` ) 
values(null , '赌神' , '龙伍' , 66.5, 125 , 535);select * from t_user;
select * from t_book;

逆向工程配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!--targetRuntime 可以设置生成的版本MyBatis3         豪华版  除了CRUD还有很多有用的查询方法MyBatis3Simple   标配版   只有CRUD--><context id="DB2Tables" targetRuntime="MyBatis3"><!-- 去掉全部的注释 --><commentGenerator><property name="suppressAllComments" value="true" /></commentGenerator><!--修改 数据库的 连接属性--><jdbcConnection driverClass="com.mysql.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/mbg"userId="root"password="root"></jdbcConnection><javaTypeResolver ><property name="forceBigDecimals" value="false" /></javaTypeResolver><!--配置生成javaBean的targetPackage javaBean的包名targetProject 生成在哪个项目目录下--><javaModelGenerator targetPackage="com.atguigu.pojo" targetProject=".\08-mybatis-mbg\src"><property name="enableSubPackages" value="true" /><property name="trimStrings" value="true" /></javaModelGenerator><!--配置生成的Mapper.xml配置文件targetPackage javaBean的包名targetProject 生成在哪个项目目录下--><sqlMapGenerator targetPackage="com.atguigu.mapper"  targetProject=".\08-mybatis-mbg\src"><property name="enableSubPackages" value="true" /></sqlMapGenerator><!--配置生成Mapper接口targetPackage Mapper接口的包名targetProject 生成在哪个项目目录下--><javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mapper"targetProject=".\08-mybatis-mbg\src"><property name="enableSubPackages" value="true" /></javaClientGenerator><!--数据库一个表对应一个table标签tableName是表名domainObjectName 设置生成的类名--><table tableName="t_user" domainObjectName="User" /><table tableName="t_book" domainObjectName="Book" /></context>
</generatorConfiguration>

执行逆向工程的代码:

package com.atguigu.mbg.runner;import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;public class MbgRunner {public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {List<String> warnings = new ArrayList<String>();boolean overwrite = true;File configFile = new File("08-mybatis-mbg/mbg.xml");ConfigurationParser cp = new ConfigurationParser(warnings);Configuration config = cp.parseConfiguration(configFile);DefaultShellCallback callback = new DefaultShellCallback(overwrite);MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);myBatisGenerator.generate(null);}
}

在这里插入图片描述
土豪金版本的测试代码:

package com.atguigu.test;import com.atguigu.mapper.BookMapper;
import com.atguigu.pojo.Book;
import com.atguigu.pojo.BookExample;
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.BeforeClass;
import org.junit.Test;import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;public class BookMapperTest {static SqlSessionFactory sqlSessionFactory;@BeforeClasspublic static void init() throws IOException {sqlSessionFactory= new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));}@Testpublic void countByExample() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);// 创建一个条件类BookExample bookExample = new BookExample();// 创建一个查询条件BookExample.Criteria criteria = bookExample.createCriteria();//            where xxx = xxx and xxx = xxx;
//            where xxx = xxx or xxx = xxx;// 查询价格大于16的图书有几条记录
//            criteria.andPriceGreaterThan(new BigDecimal(16));// 查询销量大于10 , 且 库存 大于50的记录
//            criteria.andSalesGreaterThan(10);
//            criteria.andStockGreaterThan(50);// 查询销量大于10 , 或 库存 大于50的记录criteria.andSalesEqualTo(10);bookExample.or().andStockGreaterThan(50);// count() 用于查询数量的方法// count 用于查询数量的// ByExample按条件来查询int i = mapper.countByExample(bookExample);System.out.println(i);} finally {session.close();}}@Testpublic void deleteByExample() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);
//            mapper.deleteByExample(null);// 只要条件是空,就是全表操作BookExample bookExample = new BookExample();bookExample.createCriteria().andSalesGreaterThan(10000);mapper.deleteByExample(bookExample);session.commit();} finally {session.close();}}@Testpublic void deleteByPrimaryKey() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);mapper.deleteByPrimaryKey(8);session.commit();} finally {session.close();}}@Testpublic void insert() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);mapper.insert(new Book(null,"拐跑别人媳妇", "陈凯", new BigDecimal(1234), 1234,1234));mapper.insert(new Book(null,"伟德渣男记", "王灿侨", new BigDecimal(1234), 1234,1234));session.commit();} finally {session.close();}}@Testpublic void insertSelective() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);Book book = new Book(null,"国哥是怎样炼成的", null,null,100,100);// 方法末尾Selective就表示操作的时候,不带null值的列
//            mapper.insertSelective(book);// null列不在操作范围内mapper.insert(book);// null列一样在操作范围内session.commit();} finally {session.close();}}@Testpublic void selectByExample() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);BookExample bookExample = new BookExample();bookExample.createCriteria().andIdBetween(1,10);// 设置排序字段bookExample.setOrderByClause(" price desc ");
//            List<Book> books = mapper.selectByExample(null);// 条件为null,就整表操作List<Book> books = mapper.selectByExample(bookExample);// 有条件books.forEach(System.out::println);} finally {session.close();}}@Testpublic void selectByPrimaryKey() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);Book book = mapper.selectByPrimaryKey(6);System.out.println(book);} finally {session.close();}}@Testpublic void updateByExampleSelective() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);Book book = new Book(null,"忽略null的列", null, null,1234,124);BookExample bookExample = new BookExample();bookExample.createCriteria().andIdGreaterThan(8);/*** 根据条件来进行更新,而且不带null的列*/mapper.updateByExampleSelective(book,bookExample);session.commit();} finally {session.close();}}@Testpublic void updateByExample() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);Book book = new Book(null,"忽略null的列", null, null,1234,124);BookExample bookExample = new BookExample();bookExample.createCriteria().andIdGreaterThan(8);/*** 根据条件来进行更新,而且不带null的列*/mapper.updateByExample(book,bookExample);session.commit();} finally {session.close();}}@Testpublic void updateByPrimaryKeySelective() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);Book book = new Book(null,"忽略null的列", null, null,1234,124);/*** 根据条件来进行更新,而且不带null的列*/mapper.updateByPrimaryKeySelective(book);session.commit();} finally {session.close();}}@Testpublic void updateByPrimaryKey() {SqlSession session = sqlSessionFactory.openSession();try {BookMapper mapper = session.getMapper(BookMapper.class);Book book = new Book(null,"忽略null的列", null, null,1234,124);/*** 根据条件来进行更新*/mapper.updateByPrimaryKey(book);session.commit();} finally {session.close();}}
}

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/101478.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息