简介
- 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缺点
硬编码:注册驱动,获取连接;SQL语句
操作繁琐 :手动设置参数;手动封装结果集
MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作
MyBatis快速入门
下边通过查询表中所有数据来快速认识MyBatis,在MyBatis中文网中有较为详细的步骤。
创建表
在MySQL数据库中创建一个表,并在表中添加数据
创建模块 导入坐标
创建一个模块,将坐标导入到pom.xml文件中。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>
</dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
编写核心配置文件
编写核心配置文件用来替换连接信息解决硬编码问题。
在resources目录下创建一个新的xml文件,可以任意命名(一般命名为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.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/secondTable"/> <!--当连接的是本机且端口号为默认的3306时localhost:3306可以省略不写,secondTable是数据库名-->
<property name="username" value="${username}"/> <!--用户名-->
<property name="password" value="${password}"/> <!--密码-->
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/> <!--SQL映射文件的位置-->
</mappers>
</configuration>
编写SQL映射文件
编写SQL映射文件用来统一管理sq|语句,解决硬编码问题
在resources目录下创建一个新的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="BlogMapper"> <!--BlogMapper是一个名称,可以任意修改-->
<select id="seLectALl" resultType="com.GLATY.student.Hero"> <!--seLectALl为唯一识别标识,Hero为返回的类名称-->
select * from Heros; <!--SQL中的select语句。Idea没有配置数据库时会报错,配置数据库后即可-->
</select>
</mapper>
编码
定义Hero类;加载核心配置文件,获取SqlSessionFactory 对象;获取SqlSession对象,执行SQL语句;释放资源。
public static void main(String[] args) throws Exception{
//加载MyBatis核心文件,获取SqlSessionFactory。
String resource = "mybatis-config.xml"; //要于前边resources目录下创建的xml文件名相同
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession对象,用它来执行SQL语句。
SqlSession sqlSession = sqlSessionFactory.openSession(); //()中可填true或false,表示自动提交事务是否开启。不填默认不自动提交。
//执行SQL
List<Hero> Heros= sqlSession.selectList("test.selectAll");
System.out.println(Heros); //打印查看
//释放资源
sqlSession.close();
}
Mapper代理开发
优点
解决原生方式中的硬编码
简化后期执行SQL
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Hero> Heros= sqlSession.selectList("test.selectAll");
//上列代码可改为下列形式,设置SQL语句的id将会成为userMapper中的一个方法
UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //获取接口代理对象
//调用userMapper中的方法即可
List<Hero> Heros= userMapper.seLectALl();
要求
1. 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下(接口放在Java包中,SQL映射文件放在resources包中与接口在Java包中同名的一个包中)
2. 设置SQL映射文件的namespace属性为Mapper接口全限定名(还要经核心配置文件中填的SQL映射文件的位置该成相应的地方)
<mapper namespace="com.GLATY.Mapper.TestMapper">
<select id="selectAll" resultType="com.GLATY.student.Hero">
select * from secondtable.hero;
</select>
</mapper>
<mappers>
<!--SQL映射文件-->
<mapper resource="com/GLATY/Mapper/TestMapper.xml"/>
</mappers>
3. 在Mapper接口中定义方法,方法名就是SQL映射文件中sq|语句的id,并保持参数类型和返回值类型一致
public interface TestMapper {
List<Hero> selectAll();
}
4. 编码:通过SqlSession的getMapper方法获取Mapper接口的代理对象;调用对应方法完成sql的执行
TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
List<Hero> Hero1 = testMapper.selectAll();
如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载
<mappers>
<!--SQL映射文件-->
<!--<mapper resource="com/GLATY/Mapper/TestMapper.xml"/>-->
<package name="com.GLATY.Mapper"/>
</mappers>
MyBatis核心配置文件
配置各个标签时,需要遵守前后顺序
标签顺序:
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
environments
配置数据库连按环境信息。可以配置多个environment,通过default属性切换不同的environment
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/secondTable"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<environment id="other">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/otherTable"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
typeAliases
typeAliases(类型别名):可为 Java 类型设置一个缩写名字(不区分大小写)。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>
<!--如上配置时Author可以用在任何使用domain.blog.Author的地方,Blog可以用在任何使用domain.blog.Blog的地方,-->
<!--也可以指定一个包名,MyBatis会在包名下面搜索需要的Java Bean-->
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
增删改查
增删改查可以通过配置文件或注解这两种方式完成。
在idea中下载一个MyBatisX插件更方便。
配置文件
查询
查询所有数据
编写接口方法:Mapper接口
参数:无
结果:List集合
//方法
List<Hero> selectAll();
编写SQL语句:SQL映射文件
<!--statement-->
<select id="selectAll" resultType="Hero">
select * from hero;
</select>
*数据库表的字段名称和实体类的属性名称不一样, 则不能自动封装数据,可以通过起别名解决。
起别名:在写SQL语句时对不一样的列名起别名,让别名和实体类的属性名一样。为了避免每次查询都要起一次别名可以在SQL映射文件中sql片段(不灵活)
<mapper namespace="com.GLATY.Mapper.TestMapper">
<!--sql片段-->
<sql id="All">
name, id, codeName
</sql>
<select id="selectAll" resultType="Hero">
select <include refid="All" /> from secondtable.hero;
</select>-->
</mapper>
resuitMap:先定义<resuLtMap>标签,以后在<seLect>标签中使用resultMap属性替换resultType属性
<resultMap id="HeroResultMap" type="Hero"> <!--id为唯一标识,type是映射的类型(可以用别名)-->
<!--id:完成主建字段的映射
result:完成一般字段的映射
-->
<result column="code_name" property="codeName" /> <!--column为表的列名,property为实体类的属性名-->
</resultMap>
<select id="selectAll" resultMap="HeroResultMap">
select * from secondtable.hero;
</select>
查询指定数据
编写接口方法:Mapper接口
参数:id
结果:Hero
//接口方法
List<Hero> selectAll(int id);
编写SQL语句:SQL映射文件
<!--statement-->
<select id="selectAll" resultType="Hero">
select * from hero where id = #{id};
</select>
*参数占位符
#{}:会将其替换为?,可以防止SQL注入
${}:直接拼接sqL,会存在SQL注入问题
使用时机:参数传递的时候用#{},表名或者列名不固定的情况下用${}(会存在SQL注入问题)
表名或者列名不固定的情况下: ${}会存在SQL注入问题
*特殊字符处理
当SQL语句中用到了XML文件中的特殊符号时不可以直接使用,可以通过下列两种方法写
使用转义字符(写<时用<代替)
使用CDATA区,将特殊符号写在<![CDATA[ ]]>(CDATA[]中[]中的内容将会被当做纯文本文档)
多条件查询
编写接口方法:Mapper接口
参数:多参数
结果:List集合
//接口方法
//散装参数
List<Hero> selectByCondition(@Param("ability")int ability, @Param("name")String name, @Param("codeName")String codeName);
//对象参数
//map集合参数
编写SQL语句:SQL映射文件
<select id="selectByCondition" resultMap="HeroResultMap">
select *
from secondtable.hero
where ability = #{ability}
and name like #{name}
</select>
*参数接收(散装参数、对象参数、map集合参数)
散装参数:如果方法中有多个参数,需要使用@Param("SQL参数占位符名称")
对象参数:对象的属性名称要和参数占位符名称一致
map集合参数:只需要保证SQL 中的参数名和map集合的键的名称对应 上,即可设置成功
动态查询
if: 条件判断(判断语句是否执行) test: 逻辑表达式
where:解决and的语法错误,永<where>标签代替where
<select id="selectByCondition" resultMap="HeroResultMap">
select *
from secondtable.hero
<where>
<if test="ability != null">
and ability = #{ability}
</if>
<if test="name != null and name != ''">
and name like #{name}
</if>
<if test="codeName != null and codeName != ''">
and code_name like #{codeName}
</if>;
</where>
</select>
choose:进行单条件动态查询
<select id="selectByOneCondition" resultMap="HeroResultMap">
select *
from secondtable.hero
<where>
<choose> <!--类似于Java中的switch*-->
<when test="ability != null"> <!--when类似于Java中的case-->
ability = #{ability}
</when>
<when test="name != null and name != ''">
name like #{name}
</when>
<when test="codeName != null and codeName != ''">
and code_name like #{codeName}
</when>
<otherwise> <!--otherwise类似于Java中的default-->
1 = 1
</otherwise>
</choose>
</where>
</select>
添加
编写接口方法:Mapper接口
参数:添加的参数
结果:void
void add(Hero hero);
编写SQL语句:SQL映射文件
<insert id="add">
insert into secondtable.hero(name, id, code_name, ability) values(#{name}, #{id}, #{code_name}, #{ability})
</insert>
*在执行完SQL语句后要提交事务,jdbc默认事务要手动提交。
Hero hero2 = new Hero();
hero2.setName("Name3306");
hero2.setCodeName("3306");
hero2.setAbility(10);
testMapper.add(hero2);
sqlSession.commit(); //提交事务
*返回添加数据的主键,需要将SQL映射文件像下方一样添加两个属性即可
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into secondtable.hero(name, id, code_name, ability) values(#{name}, #{id}, #{code_name}, #{ability})
</insert>
修改
修改全部字段
编写接口方法:Mapper接口
参数:所有数据
结果:void
void updateAll(Hero hero);
编写SQL语句:SQL映射文件
<update id="updateAll">
update secondtable.hero set name = #{name}, code_name = #{codeName}, ability = #{ability} where id = #{id}
</update>
*在执行完SQL语句后要提交事务
修改动态字段
在SQL映射文件中使用set标签与if标签
<update id="updateOneOrSome">
update secondtable.hero
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="codeName != null and codeName != ''">
code_name = #{codeName},
</if>
<if test="ability != null">
ability = #{ability}
</if>
<where>
id = #{id}
</where>
</set>
</update>
删除
删除一个
编写接口方法:Mapper接口
参数:id
结果:void
void deleteOne(int id);
编写SQL语句:SQL映射文件
<delete id="deleteOne">
delete from secondtable.hero where id = #{id};
</delete>
*在执行完SQL语句后要提交事务
批量删除
编写接口方法:Mapper接口
参数:id数组
结果:void
void deleteSomeById(@Param("ids") int[] ids);
编写SQL语句:SQL映射文件
需要用foreach标签
<delete id="deleteSomeById">
delete from secondtable.hero
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
<!--collection为遍历的数组,item为遍历的元素名,separator为分隔符,open为开始时拼接的内容,close为结束时拼接的内容-->
#{id}
</foreach>
</delete>
*mybatis会将数组参数,封装为一个Map集合。集合名默认为array,可以使用@Param改变名称
*参数传递
MyBatis接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理方式
MyBatis提供了ParamNameResolver类来进行参数封装
单个参数
POJO类型:直接使用,属性名和参数占位符名称一致
Map集合:直接使用,键名和参数占位符名称一致
Collection:封装为Map集合可以用@Param()替换Map集合中默认的rag键名
{"arg0",collection集合}、{"collection",collection集合}
List:封装为Map集合可以用@Param()替换Map集合中默认的rag键名
{"arg0",list集合}、{"collection",list集合}、{"list",list集合}
Array:封装为Map集合,可以用@Param()替换Map集合中默认的rag键名
{"arg0",数组}、{"array",数组}
其他类型:直接使用
多个参数
封装为Map集合,每个值都被封装成了两个键值对,
对于第n个数据的键值对为{"arg(n - 1)",值}、{"paramn",值}。
用@Param()后键值对{"arg(n - 1)",值}的键会改为相应的注解
注解
使用注解开发会比配置文件开发更加方便,使用注解只需要在方法上边加入相应的注解即可,比如:
@Select("select * from secondtable.hero where id = #{id}")
Hero selectOneById(int id);
- 查询:@Select
- 添加:@Insert
- 修改:@Update
- 删除:@Delete
使用注解来映射简单语句会使代码显得更加简洁,但如果需要做一些很复杂的操作, 最好用XML来映射语句。