一、Mybatis简介
1.什么是 MyBatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
【tips】持久层:JavaEE的三层架构是表现层、业务层、持久层,持久层就是负责将数据保存到数据库的那一层代码。
2.JDBC的不足
(1)硬编码:
1)注册驱动,获取连接
2)SQL语句
(2)操作繁琐:
1)手动设置参数
2)手动封装结果
3.MyBatis的简化
MyBatis用配置文件来解决硬编码问题,自动完成设置参数(不再一个一个地设置参数)和封装数据的操作。
二、MyBatis核心配置文件
1.核心配置文件的作用?
MyBatis 的配置文件(官网写为mybatis-config.xml)描述了 MyBatis 行为的设置和属性信息。可以在MyBatis官网(https://mybatis.net.cn/configuration.html)查看。
2.配置文档的顶层结构
【注意】配置文档标签的前后顺序不能改变!
(1)typeAliases:可以为 Java 类型设置一个别名,配置好后不区分大小写。
(2)environments:配置数据库连接环境信息,可以配置多个数据库environment,通过default属性切换不同的environment。
(3)mappers:配置映射文件信息。
三、MyBatis的使用
1.使用MyBatis实现查询所有的操作
(1)创建tb_user表,添加数据;
(2)创建模块,在pom.xml中配置坐标;
1)mybatis依赖坐标
2)MySQL驱动坐标
3)Junit单元测试坐标
4)logback依赖坐标
(3)编写MyBatis核心配置文件——mybatis-config.xml :
从 mybatis-config.xml 中构建 SqlSessionFactory,将XML配置文件放到类路径下的资源文件(src\main\resources),该配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。
(4)编写sql映射(mapper)文件——UserMapper.xml:
1)将SQL语句写到.xml文件里:
<!-- namespace:名称空间 --> <mapper namespace="test"> <!--定义sql语句--> <!-- id:sql语句的唯一标识 resultType:返回结果的类型 --> <select id="selectAll" resultType="selectAll_Demo.pojo.User"> select * from tb_user; </select> </mapper>
【tips】①在使用mybatis的时候,会使用到#{}和${}这两个符号来为SQL语句传参数,那么这两者有什么区别呢?
a.#{}是预编译处理,是占位符;${}是字符串替换,是拼接符;
b.Mybatis在处理#{}的时候会将sql中的#{}替换成"?",调用PreparedStatement来赋值,可以防止SQL注入;在处理${}的时候就是把${}替换成变量的值,调用Statement来赋值;
所以在对SQL语句进行参数传递的时候,要用#{参数}!
②where条件判断时,对于特殊字符的处理(如小于号<会被当成标签的开始):
a.转义字符
b.CDATA区:<![CDATA[ 内容 ]]>
2)将sql映射(mapper)文件加载进MyBatis核心配置文件:
(5)编码:
1)定义POJO类;
2)加载mybatis核心配置文件,获取SqlSessionFactory对象:
固定代码,用就复制:
String resource = "mybatis-config.xml";//mybatish核心配置文件的路径 InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(inputStream);
3)获取SqlSession对象用来执行sql语句:
使用SqlSessionFactory的openSession方法获取SqlSession对象(类似JDBC里的Statement对象):
//获取SQLSession对象,用其执行SQL语句 SqlSession ss = ssf.openSession(); //执行SQL语句 //查询所有 List<User> users = ss.selectList("test.selectAll");//传入SQL语句的唯一标识(id),记得带上名称空间(namespace)
【tips】MyBatis事务:在使用openSession方法获取SQLSession对象时,可以通过true和false来设置是否自动提交事务。
//获取SQLSession对象 SqlSession sqlSession = ssf.openSession(true);//自动提交事务
4)释放SqlSession资源。
2.resultMap映射(★)
在Mapper接口的配置文件中定义SQL语句时,如果数据库表的列名和实体类的属性名(如brand_name和brandName)不一样,则MyBatis就不能自动封装数据,最终查询到的结果会为null。
利用resultMap可以将不一样的列名映射为属性名,解决列名和属性名不一样的问题。步骤:
(1)在Mapper接口的配置文件中定义<resultMap>标签;
(2)在<select>标签中把resultType属性改为resultMap属性。
<mapper namespace="selectAll_Demo.mapper.UserMapper"> <!--在Mapper接口的配置文件中定义<resultMap>标签--> <!-- id:resultMap的唯一标识; type:映射的类型,支持别名; --> <resultMap id="userResultMap" type="selectAll_Demo.pojo.User"> <!-- id:完成主键字段的映射 column:表的列名 property:实体类的属性名 result:完成一般字段的映射 column:表的列名 property:实体类的属性名 --> <result column="user_name" property="username"/> </resultMap> <!--在<select>标签中把resultType属性改为resultMap属性--> <select id="selectAll" resultMap="userResultMap"> select * from tb_user; </select> </mapper>
【tips】使用注释开发时,在实现类的方法上用注释@ResultMap("userResultMap")来代替步骤(2)。
3.Mapper代理开发
(1)解决了原生MyBatis使用时的硬编码问题(如图)和简化了后期执行SQL语句的操作,可以直接通过sql映射文件里的SQL语句的唯一标识来执行SQL语句。
(2)使用Mapper代理的步骤:
1)定义与sql映射文件同名的Mapper接口,并将sql映射文件和Mapper接口的字节码文件(.class)放在同一目录下:
【tips】将二者放在同一目录下时,不建议直接把XML拖过去,因为在Maven的项目结构里是把Java代码和配置文件分开管理的。编译后,resources里的配置文件和Java代码是在同一个classes文件夹里面(如图),所以要把二者放在同一目录下,只需要在resources里新建一个跟mapper存放路径一样的包结构(如图2)(★★★★★)。
2)设置sql配置文件的namespace属性值为Mapper接口全限定名(带路径):
这样就将sql映射文件和nmapper联系起来了。
3)在Mapper接口中定义方法,这些方法是用来使用SQL语句的,方法名就是sql映射文件中SQL语句的id(为了方便调用),并保持参数类型和返回值类型一致:
(★)方法中参数接收的三种方式:
1)散装参数:如果方法需要多个参数,需要在每个参数前写上@Param("sql语句中占位符名称"),来规定该参数传给SQL语句中的哪个占位符:
【tips】数组参数也要@Param。
2)实体类封装参数:将需要的参数封装成一个类,类中的属性名要与占位符名称一致:
3)Map集合对象参数:将需要的参数和值封装成一个Map集合,集合中的键名要与占位符名称一致:
4)编码:
①加载核心配置文件,获取SqlSessionFactory对象
②获取SQLSession对象
③获取Mapper接口的代理对象;
④调用接口中的方法执行SQL语句。
//获取UserMapper接口的代理对象 UserMapper userMapper = ss.getMapper(UserMapper.class); //执行SQL语句 List<User> users = userMapper.selectAll();
4.返回添加数据的主键值
在<insert>标签中添加useGeneratedKeys属性和keyProperty属性:
- useGeneratedKeys:true(默认为false)表示插入数据时,mybatis可以自动获取从数据库生成的主键。
- keyProperty:主键名。
5.动态SQL语句
动态SQL语句指的是能根据输入条件而动态变化的SQL语句。实现动态SQL语句的标签:
(1)if:用来判断参数是否有值,使用test属性进行条件判断,满足test条件才执行if标签内的语句。
【注意】test中的条件判断写的是传入的参数,而不是列名。
【tips】在有逻辑运算符连接的多个where条件判断时,如果第一个条件不满足test条件,直接执行带逻辑运算符的第二个条件,这时where直接跟了逻辑运算符,这样就会报错,那么如何解决呢?
①恒等式:在where后加一个恒等式条件(如1 = 1):
②用<where>标签代替where关键字:
(2)choose (when, otherwise):可以从多个条件中选择一个条件进行查询,类似switch语句,其中when类似case,otherwise类似default:
(3)trim (where, set):<trim>标签一般用于去除SQL语句中多余的and关键字、逗号或者给SQL语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于动态插入、更新、删除或者条件查询等操作。
(4)foreach:用于遍历数组
【各属性名及含义见6.(2)】
6.批量删除(★)
(1)接口方法的参数:id数组
(2)sql映射文件中SQL语句的编写:
<!--批量删除--> <delete id="deleteByIds"> delete from tb_brand where id in <!-- collection:要遍历的集合名 item:集合中每一个元素进行遍历时的别名 separator:表示在每次进行遍历之间以什么符号作为分隔符 open/close:表示该语句以什么开始/以什么结束 --> <foreach collection="array" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete>【tips】★★在MyBatis中会将数组参数封装成一个Map集合,默认键名为array,array对应的值就是被封装的数组。所以在使用foreach遍历数组时,collection属性要写数组对应的键即collection=array。
【tips】如果想自定义Map中的键名,可以在定义Mapper接口方法时,用@Param("新键名")注解来重命名键名,然后collection属性就可以写"新键名"了。
//批量删除 void deleteByIds(@Param("ids") int[] ids);
<!--批量删除--> <delete id="deleteByIds"> delete from tb_brand where id in <!--collection="新键名"--> <foreach collection="ids" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete>
7.MyBatis参数传递
MyBatis底层对于不同类型参数的封装方式不同:
(1)单个参数:
1)pojo类型:直接使用,实体类的属性名和参数占位符的名称一致。
2)Map集合:直接使用,键名和参数占位符的名称一致。
3)Collection集合:封装成Map集合:
map.put("collection",collection集合); map.put("arg0",collection集合);
4)List集合:封装成Map集合:
map.put("collection",list集合); map.put("list",list集合); map.put("arg0",list集合);
5)Array:封装成Map集合:
map.put("array",数组); map.put("arg0",数组);
6)其他类型,如int:直接使用。
(2)多个参数:
封装为Map集合:
封装为Map集合:
map.put("arg0",参数值1); map.put("param1",参数值1); map.put("arg1",参数值2); map.put("param2",参数值2);【tips】被封装成Map集合的参数,一般都用@Param("新键名")注解来修改Map集合中默认的键名,并用新键名来获取值。
8.注解开发
(1)在Mapper接口中定义方法时,用注解来写SQL语句:
【tips】@ResultMap("resultMap_id")可以解决SQL语句字段名与pojo类属性名不一致的问题。
(2)注解开发适用于简单的SQL语句,配置文件开发适用于复杂的SQL语句。