MyBatis
什么是MyBatis?
- MyBatis是一款优秀的持久层框架,用于简化JDBC开发
- MyBatis 本是 Apache 的一个开源项目iBatis, 2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github
- 官网:https://mybatis.org/mybatis-3/zh/index.html
持久层
- 负责将数据到保存到数据库的那一层代码
- JavaEE三层架构:表现层、业务层、持久层
框架
- 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
- 在框架的基础之上构建软件编写更加高效、规范、通用、可扩展
JDBC 缺点
1.硬编码
- 注册驱动,获取连接
- SQL语句
2.操作繁琐
- 手动设置参数
- 手动封装结果集
MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作
MyBatis快速入门
-
创建表mybatisdemo数据库,创建user表,添加数据
-
创建模块,导入坐标
//pro.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!--当前项目坐标--> <groupId>org.jihua</groupId> <artifactId>mavendemo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <!--导入MySQL驱动jar包--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> <!--导入druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!--导入junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> <!--mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <!--添加slf4j日志api--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> </dependency> <!--添加logback-classic依赖--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <!--添加logback-core依赖--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> </dependencies> </project>
-
编写MyBatis核心配置文件---->替换连接信息解决硬编码问题
//mybatis-config.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> <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:///mybatisdemo?useSSL=false"/> <property name="username" value="root"/> <property name="password" value="修改为你的密码"/> </dataSource> </environment> </environments> <mappers> <!--加载sql映射文件--> <mapper resource="UserMapper.xml"/> </mappers> </configuration>
-
编写SQL映射文件---->统一管理sql语句,解决硬编码问题
//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:名称空间 --> <mapper namespace="demo"> <select id="selectAll" resultType="com.jihua.pojo.User"> select * from tb_user </select> </mapper>
-
编码
(1) 定义POJO类
//User类 package com.jihua.pojo; public class User { private Integer id; private String username; private String password; private String gender; private String addr; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", gender='" + gender + '\'' + ", addr='" + addr + '\'' + '}'; } }
(2) main方法内
//mybatisDemo类 package com.demo; import com.jihua.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 java.io.InputStream; import java.util.List; public class mybatisDemo { public static void main(String[] args) throws Exception { //1.加载mybatis的核心配置文件,获取SqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //2.获取SqlSession对象,用它来执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); //3. 执行sql List<User> users = sqlSession.selectList("demo.selectAll"); System.out.println(users); //4. 释放资源 sqlSession.close(); } }
Mapper代理开发
目的
- 解决原生方式中的硬编码
- 简化后期执行SQL
使用Mapper 代理方式完成入门案例
-
定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置
同—目录下-
新建UserMapper接口,放在src/main/java/com/jihua/Mapper下
-
将UserMapper.xml文件放在src/main/resources/com/jihua/Mapper下
- 注意:在resources目录下创建多级目录不能用
.
,要用/
,例如创建包时可以使用com.jihua.Mapper
,但是resources目录只能使用com/jihua/Mapper
-
-
设置SQL映射文件的namespace属性为Mapper接口全限定名
//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:名称空间 --> <mapper namespace="com.jihua.Mapper.UserMapper"> <select id="selectAll" resultType="com.jihua.pojo.User"> select * from tb_user </select> </mapper>
-
在 Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致
//UserMapper接口 package com.jihua.Mapper; import com.jihua.pojo.User; import java.util.List; public interface UserMapper { List<User> selectAll(); }
-
main方法中
//mybatisDemo类 package com.demo; import com.jihua.Mapper.UserMapper; import com.jihua.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 java.io.InputStream; import java.util.List; public class mybatisDemo { public static void main(String[] args) throws Exception { //1.加载mybatis的核心配置文件,获取SqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //2.获取SqlSession对象,用它来执行sql SqlSession sqlSession = sqlSessionFactory.openSession(); //3. 执行sql //3.1 通过SqlSession的getMapper方法获取Mapper接口的代理对象 UserMapper UserMapper = sqlSession.getMapper(UserMapper.class); //3.2 调用对应方法完成sql的执行 List<User> users = UserMapper.selectAll(); System.out.println(users); //4. 释放资源 sqlSession.close(); } }
细节:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载
//mybatis-config.xml文件下的mappers修改为
<mappers>
<!--加载sql映射文件-->
<!--<mapper resource="com/jihua/Mapper/UserMapper.xml"/>使用Mapper代理后弃用-->
<!--Mapper代理方式-->
<package name="com.jihua.Mapper"/>
</mappers>
MyBatis核心配置文件
MyBatis核心配置文件的顶层结构如下:.
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory (对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseldProvider (数据库厂商标识)
- mappers(映射器)
类型别名(typeAliases)
<typeAliases >
<package name="com.jihua.pojo"/>
</typeAliases>
细节:配置各个标签时,需要遵守前后顺序
配置文件完成增删改查
- 要完成的功能列表清单:
- 查询
- 查询所有数据
- 查看详情
- 条件查询
- 添加
- 修改
- 修改全部字段
- 修改动态字段
- 删除
- 删除一个
- 批量删除
- 查询
查询
数据库表的字段名称和实体类的属性名称不一样,则不能自动封装数据
-
起别名:对不一样的列名起别名,让别名和实体类的属性名一样
-
缺点:每次查询都要定义一次别名
select id, use_name as useName from tb_use;
-
-
sql片段
-
缺点:不灵活
<sql id="usenamechange"> id, use_name as neme </sql> <select id="selectAll" resultType="user"> select <include refid="usenamechange" /> from tb_user; </select>
-
-
resultMap
1.定义标签
2.在标签中,使用resultMap属性替换resultType属性resultMap属性:
- id:唯一标识
- type:映射的类型,支持别名
resultMap内部:
-
id:完成主键字段的映射
- column:表的列名
- property:实体类的属性名
-
result:完成一般字段的映射
- column:表的列名
- property:实体类的属性名
<resultMap id="nameReaultMap" type="user"> <redult column="user_name" property="userName" /> </resultMap> <select id="selectAll" resultMap="nameResultMap"> select * from tb_user; </select>
动态查询(接收传入的id值查询)
参数占位符:
- #{ }:会将其替换为?,为了防止SQL注入
- ${ }:拼sql。会存在SQL注入问题
- 使用时机:
- 参数传递的时候:#{ }
- 表名或者列名不固定的情况下:${}。会存在SQL注入问题
参数类型: parameterType:可以省略
<select id="selectById" parameterType="int" resultNap="brandResultMap">
select
*
from
tb_brand
where
id = #{id};
</select>
使用方法:
//4.执行方法
User user = userMapper.selectById(id);
system.out.println(user);
同时接口里应该有方法:
User selectById(int id);
特殊字符处理:
-
转义字符:例如
<
表示<
-
CDATA区:IDEA中敲CD直接回车
<![CDATA[ 在这里可以写小于号 ]]>
条件查询
sql语句:
<select id="selectBycondition" resultMap="brandResultMap">
select *
from tb_brand
where status = #{status}
and company_name like #{companyName}
and brand_name like #{brandName}
</select>
参数接收
-
散装参数:
如果方法中有多个参数,需要使用@Param( “SQL参数占位符名称”)
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);
-
对象参数:
接收前端传入的数据后,封装为一个对象,其中对象的属性名称要和参数占位符名称一致
List<Brand> selectByCondition(Brand brand);
-
map集合参数:
接收前端传入的数据后,封装为一个map集合,其中键的名称要和参数占位符名称一致
List<Brand> selectByCondition(Map map) ;
多条件动态查询
当用户查询时并没有用到所有条件限制时,要采用动态SQL
SQL语句会随着用户的输入或外部条件的变化而变化,我们称为动态SQL
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where
<if test="status != null">
status = #{status}
</if>
<if test="companyName != null and companyName != '' ">
and company_name = #{companyName}
</if>
<if test="brandName != null and brandName != '' ">
and brand_name = #{brandName}
</if>
</select>
MyBatis 对动态SQL有很强大的支撑:
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
上面的代码如果第一个参数也没有传入,会导致拼接的sql语法错误
解决方法:
-
恒等式
添加一个1=1条件
<select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand where 1 = 1 <if test="status != null"> and status = #{status} </if> <if test="companyName != null and companyName != '' "> and company_name = #{companyName} </if> <if test="brandName != null and brandName != '' "> and brand_name = #{brandName} </if> </select>
-
替换where关键字
mybatis自带的条件处理
<select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand <where> <if test="status != null"> and status = #{status} </if> <if test="companyName != null and companyName != '' "> and company_name = #{companyName} </if> <if test="brandName != null and brandName != '' "> and brand_name = #{brandName} </if> </where> </select>
多条件动态查询
-
从多个条件中选择一个
-
choose (when, otherwise):选择,类似于Java中的switch语句
<select id="111" resultType="com.jihua.pojo.User"> select * from tb_user where <choose> <!--类似于switch--> <when test="status != null"><!--类似于case--> status = #{status} </when> <when test="companyName != null and companyName!=''"> company_name like #{companyName} </when> <when test="brandName != null and brandName !=''"> brand_name like #{brandName} </when> <otherwise><!--类似于default--> 1=1 </otherwise> </choose> </select>
添加
MyBatis事务:
在获取sqlSession对象时
//2.获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
openSession()
:默认开启事务,进行增删改操作后需要使用sqlSession.commit();
手动提交事务
openSession(true)
:可以设置为自动提交事务(关闭事务)
在数据添加成功后,需要获取插入数据库数据的主键的值
只需要添加两个属性:
useGeneratedKeys:开启主键返回
keyProperty:指向对应主键名称
<insert id="addOrder" useGeneratedKeys="true" keyProperty="id">
insert into tb_order (payment,paymlent_type,status) values (#{payment},#{paymentType},#{status});
</insert>
修改
:
使用set标签处理参数个数导致的sql语法问题
<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName !=''">
brand_name = #{brandName},
</if>
<if test="companyName != null and companyName !=''">
company_name = #{companyName},
</if>
<if test="ordered != null">
ordered = #{ordered},
</if>
<if test="description != null and description !=''">
description = #{description},
</if>
<if test="status != null">
status = #{status},
</if>
</set>
where id = #{id};
</update>
删除
<delete id="deleteById">
delete from tb_brand where id =#{id};
</ delete>
-
批量删除
传入一个id的数组
<delete id="deleteBylds"> delete from tb_brandwhere id in (?,?,?) </delete>
mybatis会将数组参数,封装为一个Map集合
-
默认::array =数组
-
或者:使用@Param注解改变map集合的默认key的名称
//定义接口方法时 void deleteByIds (@Param("ids") int[] ids);
in(?, ?, ?)中具体有多少个?,需要遍历数组,需要使用标签
<delete id="deleteBylds"> delete from tb_brand where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </delete>
separator
属性表示自动添加分隔符,open
和close
属性会加在开始和结束的位置 -
MyBatis参数传递
MyBatis 接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理方式
MyBatis参数封装:
MyBatis提供了ParamNameResolver类来进行参数封装
- 单个参数
-
POJO(数据结构)类型:直接使用,属性名和参数占位符名称一致
-
Map集合:直接使用,键名和参数占位符名称一致
-
Collection:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
map .put( "arg0" ,list集合); map.put( "collection " ,list集合);
-
List:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
map .put( "arg0" ,list集合); map .put( "collection " ,list集合); map.put( "list",list集合);
-
Array:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
map. put ( " arg0",数组);
map. put( " array ",数组);
- 其他类型:直接使用
-
多个参数:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
map.put ("arg0",参数值1); map.put("param1",参数值1); map.put("agr1",参数值2); map.put("param2",参数值2); /设置@Param ( "username " ) map.put("username",参数值1); map.put("param1",参数值1); map.put("agr1",参数值2); map.put("param2",参数值2);
建议:将来都使用@Param注解来修改Map集合中默认的键名,并使用修改后的名称来获取值,这样可读性更高!
注解完成增删改查
使用注解开发会比配置文件开发更加方便
@Select("select * from tb_user where id = #{id}")
public User selectByld(int id);
- 查询:@Select
- 添加: @Insert
- 修改:@Update
- 删除:@Delete
提示:
-
注解完成简单功能
-
配置文件完成复杂功能
-
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java注解不仅力不从心,还会让你本就复杂的SOL语句更加是盟不堪。因此,如果你需要做一些很复杂的操作,最好用XML来映射语句。
-
选择何种方式来配置映射,以及认为是否应该要统一映射语句定义的形式,完全取决于你和你的团队。换句话说,永远不要拘况于一种方式。你可以很轻松的在基于注解和XML的涯句缺射舫j方式睚自由移植和切换。