初识MyBatis框架
MyBatis是一个优秀的数据持久层框架,是一种半自动的ORM实现
-
mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
-
mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。
-
最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作
注意事项
增删改查语句使用对应标签
有参数的指定参数类型、有返回值的指定返回值类型
Sql语句中使用#{实体属性名}方式引用实体中的属性值
操作使用的API是sqlSession.对应方法(“命名空间.id”[,实体对象]);
涉及数据库数据变化的要使用sqlSession对象显示的提交事务,即sqISession.commit()
添加mybatis相关依赖
添加mybatis核心配置文件
(1)在resources目录下新建Mybaits的核心配置文件并命名为”mybatis-config.xml”
注:<configuration>是根节点,后面所有的配置都要放在<configuration>节点下
(2)编写”mybatis-config.xml”的配置内容
- 数据库连接信息配置
- SQL语句映射文件地址配置<mappers> <mapper resource="" /> </mappers>
- ”mybatis-config.xml”的配置节点说明
- configuration:配置文件的根元素节点
- environments:表示配置MyBaits的多套运行环境,该元素节点下可以配置多个environment子元素节点
- environment:配置Mybaits的一套运行环境,需指定运行环境ID、事务管理(transactionManager)和数据源(dataSource)配置等相关信息
- mappers:其下可以配置多个mapper节点来具体指定SQL映射文件的路径,resource属性的值表述了类资源路径下的SQL映射文件的路径
创建业务实体类
1.在src下新建一个包,命名为”entity”,在该包下新建一个User类,用于数据的映射。
注: 1、类的名称不一定和表名相同 2、属性名称和数据库字段名称相同,才能自动映射 3、属性类型需要和数据库字段类型对应 4、每一个属性都要生成get/set方法
2.在resources下新建一个包,命名为”mapper”,在该包下新建一个SQL映射文件,命名为”UserMapper.xml”
编辑”UserMapper.xml”文件头
注:<mapper>是根节点,后面所有的SQL映射配置都要放在<mapper>节点下
3.SQL映射内容(查询所有用户)
配置节点说明: select:表示查询语句 id属性:表示该SQL语句的唯一标识符 resultType属性:表示SQL语句返回值类型,此处通过SQL语句查询数据,将数据直接映射到User实体类上
代码测试
在test下新建一个包,命名为”test”,在test包下新建一个测试类,命名为”UserMapperTest”,并添加一个测试方法
测试结果
测试类中使用Mybaits执行SQL的步骤如下:
Mybaits框架的特点
- 开源的优秀持久层框架
- 面向配置编程
- SQL语句与代码分离,方便维护
- 良好支持数据映射,结果处理方便
- 支持动态SQL语句
核心配置文件结构
configuration 根节点
- properties 可以配置在Java 属性配置文件中
- settings 修改 MyBatis 在运行时的行为方式
- typeAliases 为 Java 类型命名一个别名(简称)
- typeHandlers 类型处理器
- objectFactory 对象工厂
- plugins 插件
- environments 环境
- environment 环境变量
- transactionManager 事务管理器
- dataSource 数据源
- mappers 映射器
typeAliases元素
指定entity.User的别名为user
<typeAliases>
<typeAlias type="entity.User" alias="user"></typeAlias>
</typeAliases>
减少SQL映射文件中输入多余的完整类名,简化操作
<select id="findAllUser" resultType="user">
select * from user
</select>
通过package的name属性直接指定包名,Mybatis会自动扫描指定包下的JavaBean,并设置一个别名,默认名称为非限定类名
<typeAliases>
<package name="entity"/>
</typeAliases>
properties元素
properties元素描述的都是外部化、可替代的属性
属性文件:
- 文件后缀为.properties
- 这种文件以key=value格式存储内容
将数据库连接参数信息放在单独的属性文件(.properties)中
1.编辑”database.properties”,填写数据库连接参数信息(键值对)
2.编辑”mybatis-config.xml”,加入properties标签,注意放在<typeAliases>标签上面
3.编辑”mybatis-config.xml”,使用${}占位符和属性文件中的键名来实现动态配置
MyBatis条件查询
查询用户信息表user中用户名为“张三”的记录并输出
步骤1:
- 在映射文件的SQL配置中配置参数 使用parameterType来指定参数类型
- 使用#{参数名}来接收参数的值
parameterType="string" 表示sql语句需要一个参数,类型为字符串
username=#{xxx}表示用户名的值是来自一个变量xxx,这个变量值直接从java代码中传入,变量名可以任意命名,因为只有一个变量,会自动识别传过来的参数
步骤2:在测试类”UserMapperTest”中,新加入一个测试方法
@Test
public void findUserByUserName() throws IOException {
//1.加载mybatis核心配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//2.获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.得到执行sql的对象SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.执行sql语句
List<User> list = sqlSession.selectList("userMapper.findUsername","张三");
//5.处理结果
for (User user: list) {
System.out.println("用户名:"+user.getUsername()+",密码:"+user.getPassword());
}
//6.关闭数据库会话
sqlSession.close();
}
parameterType属性
- 表示查询语句传入参数的类型。
- 支持基础数据类型和复杂数据类型
- 如果SQL是单条件查询,则parameterType指定为基础数据类型
- 对于常用的java类型,mybatis都定义了类型别名:
多条件查询
查询用户信息表user中性别为“女性”,“1996”年出生的记录并输出
多条件查询时,parameterType的参数类型可以为如下两种:
- 使用Java自定义实体类
- 使用map或者hashmap
使用Java自定义实体类 传递参数
1.在entity包下自定义Java实体类”UserCnd”,用于承载查询参数
注:需要传递几个参数,就定义几个属性,属性的类型和传递参数的类型一致
2.在映射文件”UserMapper.xml”中新增select配置
注:
parameterType指定为自定义实体类” UserCnd”
#{sex}表示性别条件的值取自实体类对象中sex属性的值
#{birthYear}表示出生年份条件的值取自实体类对象中birthYear属性的值
3.在测试类”UserMapperTest”中,新加入一个测试方法
使用map/hashmap 传递参数
1.在映射文件”UserMapper.xml”中新增select配置
注:
parameterType指定为”map”或者”hashmap”
#{sex}表示性别条件的值取自map对象中键名为sex的值
#{birthYear}表示出生年份条件的值取自map对象中键名为birthYear的值
2.在测试类”UserMapperTest”中,新加入一个测试方法
MyBatis传入参数类型(parameterType)总结
查询结果映射
查询结果映射是指MyBatis自动将SQL语句查询出来的结果映射到指定的对象中。
resultType属性
MyBatis通过resultType属性来实现查询结果的自动映射
resultType的值可以指定为两种类型:
- 基本数据类型(int、string、long等等)
- 复杂数据类型(Java实体类、map/hashmap)
查询用户信息表User中用户的总数量
1.在映射文件”UserMapper.xml”中加入Select配置
select count(1)查询结果为数量,因此resultType=”int” <select>配置中没有定义parameterType属性,因为该SQL执行不需要参数
2.在测试类”UserMapperTest”中加入测试方法
代码中通过sqlSession.selectOne执行SQL,是因为可以确保查询的结果最多只有一条记录
使用Java自定义实体类来实现结果的映射
使用map/hashmap来实现结果的映射
1.在映射文件”UserMapper.xml”中加入Select配置
resultType=”hashmap”,是指将SQL查询出来的结果以键值对的方式存入map对象中
2.在测试类”UserMapperTest”中加入测试方法
注:resultType=”hashmap”,对应的返回值的类型为Map<String,Object>
当SQL查询的结果有多列的时候,resultType的值可以为Java实体类、map/hashmap
MyBatis查询结果映射总结
自定义查询结果映射
当查询结果有多列时,可以通过自定义实体类来实现结果的自动映射
属性名和列名不一致
实体类”entity.User”中的属性名和SQL查询结果列名不一致,无法完成数据自动映射
为SQL查询出的字段定义别名,”强制”与”entity.User”中的属性名保持一致,以满足自动映射的要求
<select id="findAllUser" resultType="User">
select username as uname,password,sex,age,birthDate as birth from user
</select>
使用resultMap自定义映射关系
注:<select>节点中使用resultMap属性来指定需要使用的自定义映射关系,resultMap不能和resultType同时使用。
resultType属性和resultMap属性区别
mybatis新增操作
1.在sql映射文件UserMapper.xml中加入一个insert语句配置
注:
因为是insert语句,因此加入一个<insert>标签 insert语句需要传递5个参数,因此parameterType=”entity.User”
#{uname}表示用户名的值取自参数对象的uname属性
对于增删改操作默认resultType=”int”,代表数据操作匹配的行数,因此不需要定义resultType属性
2.在测试类中,新加入一个测试方法进行测试
mybatis的事务,对于增删改操作,默认不会自动提交到数据库执行
手动提交,需要在insert操作后加入如下代码完成手动提交: sqlSession.commit();
自动提交,需要将sqlSession设置为自动提交事务,如:SqlSession sqlSession = sqlSessionFactory.openSession(true);
mybatis修改操作
修改用户名为李四的记录,把密码修改为666,年龄修改为30
1.在sql映射文件UserMapper.xml中加入一个update语句配置
注:
因为是update语句,因此加入一个<update>标签
update语句需要传递3个参数,因此parameterType=”map”
#{XXX}里的参数名必须要和map对象里键的名称一一对应
2.在测试类中,新加入一个测试方法
mybatis删除操作
删除姓张的所有用户记录
1.在sql映射文件UserMapper.xml中加入一个delelte语句配置
2.在测试类中,新加入一个测试方法
面向接口编程
1.在src下新建一个包,命名为”dao”。在包下新建一个接口,命名为”UserDao”
2.在”UserDao”中定义接口方法
接口方法定义规则如下: 必须保持与相应的SQL配置参数一致 方法名与id一致 方法参数与parameterType指定类型一致 方法返回值与resultType/resultMap指定映射类型一致
3.修改SQL映射文件”UserMapper.xml”,将其与接口”UserDao”关联,通过namespace属性关联。
4.在测试类中加入测试方法”testDao”,通过接口来执行SQL
MyBatis复杂查询
MyBatis框架日志配置
1.引入日志相关依赖
2.在resources文件夹中,新增log4j配置的属性文件(log4j.properties)
log4j.rootLogger=DEBUG,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.org.apache=INFO
MyBatis关联查询
关联查询【1对1】
数据库里有学生表(student)和学生证信息表(student_card)
student
student_card
查询所有的学生信息以及每位学生的学生证信息
1.创建实体
在“entity”包下新建学生(Student)实体类和学生证(StudentCard)实体类 因为两个实体类是1对1的关系,所以在Student中增加一个StudentCard类型的属性
Student
StudentCard
2.在SQL映射文件”StudentMapper.xml”中加入SQL配置如下
、
说明:
- id标签是定义数据库主键与实体中简单数据类型属性的映射关系
- result标签是定义非主键字段与实体中简单数据类型属性的映射关系
- association标签用于定义实体类型属性的映射关系。
- 在<association>标签中,property= ”studentCard” 指定复杂数据类型属性的名称。
- javaType =”entity.StudentCard”表明该属性的类型
- <association>标签内部的<id>、<result>标签用于指定查询结果列和StudentCard类型中每一个属性的映射关系
3.在”dao”包下新建接口”StudentDao”以及接口方法
【注意】 接口需要与”StudentMapper.xml”通过namespace属性关联
4.新建测试类”SelectTest”,并加入测试方法
嵌套查询实现
1.执行主查询:select * from student,获取所有学生
2.遍历主查询的结果,执行子查询:select * from student_card where stu_id=?
(1)在SQL映射文件”StudentMapper.xml”中配置子查询SQL: select * from student_card where stu_id=?
(2)在SQL映射文件”StudentMapper.xml”中配置主查询SQL:select * from student
(3)新增接口
’
(4)在测试类”SelectTest中进行测试
关联查询【1对多】
数据库里有顾客表(customer)和订单表(orders)
orders
customer
用mybatis框架查询所有的顾客信息以及每位顾客的订单信息
1.创建实体
在“entity”包下新建顾客(Customer)实体类和订单(Order)实体类
因为两个实体类是1对多的关系,所以在Customer中增加一个Order类型的列表属性
customer
orders
2.新建SQL映射文件”CustomerMapper.xml”中加入SQL配置如下 集合类型属性
说明
- id标签是定义数据库主键与实体中简单数据类型属性的映射关系
- result标签是定义非主键字段与实体中简单数据类型属性的映射关系
- collection标签用于定义集合类型属性的映射关系。
- 在<collection>标签中,property= ”orders” 指定集合数据类型属性的名称。javaType =”ArrayList”表明该属性的类型为集合。ofType=”entity.Order”表明集合中存放的数据类型。
- < collection >标签内部的<id>、<result>标签用于指定查询结果列和Order类型中每一个属性的映射关系。
3.在”dao”包下新建接口”CustomerDao”以及接口方法
【注意】 接口需要与”CustomerMapper.xml”通过namespace属性关联
4.新建测试类
resultMap标签使用总结
resultMap标签用于自定义查询结果映射关系
- 子节点id和result仅用于指定基础数据类型属性的映射关系
- 子节点id用于指定主键属性,result用于指定其他属性
- 子节点<association>标签用于处理实体类型属性的映射关系,体现实体间1对1的关系
- 子节点<collection>用于处理集合类型属性的映射关系,体现实体间1对多或者多对多的关系
动态SQL
动态SQL是MyBatis的一个强大特性 可以运用动态SQL语句标签方便我们在SQL中实现各种逻辑 常用标签如下: <if>:条件选择 <choose>:相当于Java中的switch,用于条件选择 <where>:简化SQL中的where <set>:解决动态更新语句 <trim>:灵活的去除多余的关键字 <foreach>:迭代遍历一个集合
if标签
(1)在”StudentMapper.xml”中,新增SQL配置,使用if标签配置动态SQL,如下:
(2)在”StudentDao”接口中,新增接口方法,如下:
(3)在测试类中,新增测试方法如下:
where标签
(1)在”StudentMapper.xml”中,新增SQL配置,使用if标签配置动态SQL,如下:
(2)在”StudentDao”接口中,新增接口方法如下:
(3)在测试类中,新增测试方法如下:
<where>标签能够智能的处理where、and、or,不必担心关键字导致的语法错误。
choose标签
set标签
(1)在”StudentMapper.xml”中,新增SQL配置如下:
使用set标签与if标签组合,可以智能增减要修改的字段,并智能判断逗号是否有必要存在
set标签可以智能的处理更新语句中的逗号 if+set标签组合可以实现在update语句中的动态更新 在<set>标签中的每一个修改字段前面/后面尽量加上逗号
trim标签
- trim标签:可用于拼接动态SQL语句
- 该标签有以下属性:
- prefix:前缀 suffix:后缀
- prefixOverrides:前缀覆盖,可用于智能的处理”and”,”or”关键字
- suffixOverrides:后缀覆盖,可用于处理update语句中中多余的”,”
- 作用:可以利用trim来代替<where>或者<set>的功能
foreach标签
- foreach标签的属性主要有 item,index,collection,open,separator,close。
- item表示对集合进行迭代时每一个对象的别名
- index指定一个名字,用于表示在迭代过程中,每次迭代的位置
- open是前缀,表示该语句以什么开始
- separator表示在每次迭代元素之间以什么符号作为分隔符,
- close是后缀,表示以什么结束。
- collection指定需要遍历的集合
(1)在StudentMapper.xml中新增SQL配置
说明:(1) 如果是单参数且参数类型是集合时,collection的值为list
(2) 如果是单参数且参数类型是数组时,collection的值为array
(3) 如果是多参数且参数类型是map或者实体类对象时 ,collection的值为对应map的键名或者对象的属性名
(2)在接口”StudentDao”中新增接口方法:
(3)在测试类中新增测试方法:
纯注解开发
Mybatis注解方式:
@lnsert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result一起使用,封装多个结果集
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
注意:注解方式的mapper配置可以不用在配置mapper文件地址,而是只配置包的路径。
<mappers>
<package name="com.cqgcxy.mapper"/>
</mappers>
例如
1.创建实体类:
一对一
2.创建并编写PhoneMapper接口
@Select("SELECT * FROM phone p,brand b where p.brand_id = b.brand_id")
@Results({
@Result(column = "phone_id",property = "phoneId"),
@Result(column = "model_number",property = "modelNumber"),
@Result(column = "capacity",property = "capacity"),
@Result(column = "brand_id",property = "brand.brandId"),
@Result(column = "brand_name",property = "brand.brandName"),
@Result(column = "company_name",property = "brand.companyName"),
@Result(column = "brand_idea",property = "brand.brandIdea")
})
List<Phone> selectAll();
3.创建并编写BrandMapper接口
import org.apache.ibatis.annotations.Select;
public interface BrandMapper {
@Select("SELECT * FROM brand WHERE brand_id = #{brandId}")
Brand selectById(Long brandId);
}
一对多
2.创建并编写PhoneMapper接口
@Select("SELECT * FROM phone WHERE brand_id = #{brandId}")
Phone selectByBrandId(Long brandId);
3.创建并编写BrandMapper接口
@Select("SELECT * FROM brand")
@Results({
@Result(column = "brand_id",property = "brandId"),
@Result(column = "brand_name",property = "brandName"),
@Result(column = "company_name",property = "companyName"),
@Result(column = "brand_idea",property = "brandIdea"),
@Result(column = "brand_id",
property = "phoneList",
javaType = List.class,
many = @Many(select = "com.cqgcxy.mapper.PhoneMapper.selectByBrandId")
)
})
List<Brand> selectAll();
4.编写测试类
多对多
xml方式:实现同一对多。不同点在于,多对多至少是三张表之间的关系(包含关联表)。
注解方式:实现同一对多。不同点在于,多对多@Many中的查询语句要根据条件id查询包括关联表在内的两张表。