一、原生态JDBC实现数据的增删改查
二、mybatis简介
MyBatis是一个优秀的基于ORM的半自动轻量级持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
mybatis 历史
MyBatis 本是apache的一个开源项目iBatis, 2010年6月这个项目由apache software foundation 迁移到google code,随着开发团队转投到Google Code旗下,iBatis正式改名为MyBatis ,代码于2013年11月迁移到Github
ORM(Object Relational Mapping)对象关系映射
-
O(对象模型):
实体对象,即我们在程序中根据数据库表结构建立的一个个实体javaBean
-
R(关系型数据库的数据结构):
关系数据库领域的Relational(建立的数据库表)
-
M(映射):
从R(数据库)到O(对象模型)的映射,可通过XML文件映射
实现:
(1)让实体类和数据库表进行一一对应关系
先让实体类和数据库表对应
再让实体类属性和表里面字段对应
(2)不需要直接操作数据库表,直接操作表对应的实体类对象
ORM是一种思想帮助我们跟踪实体的变化,并将实体的变化翻译成sql脚本,执行到数据库中去,也就是将实体的变化映射到了表的变化。
mybatis采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作
三、初级查询
mybatis实操,用mybatis实现对用户的增删改查
3.1执行流程
- 创建表
- 建工程,导入包依赖
- 编写实体类
- 写接口和对应的xml文件
- 建mybatis核心配置文件
- 包的别名
- 数据库环境(数据源)
- mapper配置
- 写代码
- 加载核心配置文件
- sqlSessionFactory
- SqlSession
- 调用方法
- 打印结果
- 提交事务
- 释放资源
3.2 配置文件
- properties标签
<properties resource="db.properties"/>
-
setting标签
-
typeAliases标签
-
environment标签
- environments-environment:transactionManager&dataSource
- 事务管理器: JDBC,MANAGED
- 数据源:POOLED,UNPOOLED,JNDI
- mapper标签
四、mybatis几大对象的介绍以及执行流程和原理的总结归纳
五、高级查询
- resultMap 结果集映射
5.1 、多条件查询 (sql语句中不止一个参数)
- 使用 #{arg0}-#{argn} 或者 #{param1}-#{paramn} 获取参数
select * from user where username = #{username} and password = #{password}
<select * from user where id = #{arg0} and username = #{arg1} >
<select * from user where id = #{param1} and username = #{param2} >
- 使用注解,引入 @Param() 注解获取参数
public List<User> findByIdAndUsername2(@Param("id") Integer id,@Param("username") String username);
<select id="findByIdAndUsername2" resultType="user"> select * from user where id = #{id} and username = #{username} </select>
- 使用pojo对象传递参数
public List<User> findByIdAndUsername3(User user);
<select id="findByIdAndUsername3" parameterType="com.lagou.domain.User" resultType="com.lagou.domain.User">
select * from user where id = #{id} and username = #{username}
</select>
5.2 、模糊查询
5.3、${} 与 #{} 区别【笔试题】
#{} 表示一个占位符号
- 通过 #{} 可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,
- #{}可以有效防止sql注入。
- #{} 可以接收简单类型值或pojo属性值。
- 如果parameterType传输单个简单类型值, #{} 括号中名称随便写。
${} 表示拼接sql串
- 通过 ${} 可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换,会出现sql注入问题。
- ${} 可以接收简单类型值或pojo属性值。
- 如果parameterType传输单个简单类型值, ${} 括号中只能是value。
5.4、动态Sql
一、if
- 基础语法格式
<select id="">
SELECT * FROM BLOG
WHERE state = 'ACTIVE'
<if test="title != null">
AND title like #{title}
</if>
<if test = "author != null and author_name != null">
AND author_name like #{author_name}
</if>
</select>
二、choose(when, otherwise)
-
类似于Java中的switch语句
-
只会匹配一个,即匹配到第一个符合的条件之后,就会跳过后面的。并且其中也有一个类似于DEFAULT的语句,叫做otherwise,但是在这个里面,otherwise必须有
-
基础语法
-
<select id=""> SELECT * FROM BLOG WHERE state = 'ACTIVE' <choose> <when test="title != null"> AND title like #{title} </when> <when test = "author != null and author_name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
三、trim(where, set)
- where标签,只会在子语句中有值存在的情况下,才会在最后的sql语句中,加上 WHERE 关键字,如果所有的子标签都为否,即没有子标签则不存在。
- 如果匹配成功的子句中,前面有一个AND,那么where标签会自动的将AND去掉
<select id="">
SELECT * FROM BLOG
<where>
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test = "author != null and author_name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</where>
</select>
- set标签
<update>
update Author
<set>
<if></if>
<if></if>
</set>
</update>
四、foreach
5.5 、多表查询
一对一
- 一、实现功能:根据订单查询对应的用户。一对一
- 二、Sql语句
select * from mybatis2.orders o
left join mybatis2.users u
on o.uid = u.uid
- 分析代码:
<resultMap id="orderMap" type="com.simon.entity.Order">
<id property="id" column="uid" />
<result property="orderTime" column="ordertime"/>
<result property="total" column="total"/>
<!--配置关联的属性
association 关联的属性是一个实体类
property="user"
javaType="User" 关联属性的类型
-->
<association property="user" javaType="User">
<!--这一行没有-->
<id property="id" column="uid"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</association>
</resultMap>
<!--关联查询-->
<select id="findAllOrdersAndUser" resultMap="orderMap">
select * from mybatis2.orders o
left join mybatis2.users u
on o.uid = u.uid
</select>
- 错误代码
Mapped Statements collection already contains value for com.simon.dao.OrderMapper.findAllOrdersAndUser
一对多
-
一、实现功能:根据用户找到对应的订单 一对多
-
二、代码
-
sql
select * from users u
left join orders o
on u.uid = o.uid
-
User.java
-
private Integer id; private String username; private Date birthday; private String sex; private String address; private List<Order> orders;
-
Order.java
-
private Integer id; private String orderTime; private Double total; private Integer uid;
-
被包含的即==‘多’==,
- 使用的类型是ofType,而不是javaType
- 使用的是collection而不是association
错误代码
Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property 'orders' of 'class com.simon.entity.User' with value 'Order{id=1, orderTime='2020-12-12', total=3000.0}' Cause: java.lang.IllegalArgumentException: argument type mismatch
- 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">
<mapper namespace="com.simon.dao.UserMapper">
<resultMap id="userMap" type="com.simon.entity.User">
<!--这一行没有都行,没有影响-->
<id property="id" column="uid"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<collection property="orders" ofType="com.simon.entity.Order">
<id property="id" column="id" />
<result property="orderTime" column="ordertime"/>
<result property="total" column="total"/>
<result property="uid" column="uid"/>
</collection>
</resultMap>
<!--关联查询-->
<select id="findOrderByUser" resultMap="userMap">
select * from mybatis2.users u
left join mybatis2.orders o
on u.uid = o.uid
</select>
</mapper>
-
Test.java
-
@Test public void orderToUserTest(){ SqlSession sqlSession = MybatisUtil.get_sqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.findOrderByUser(); for (User user : users) { System.out.println(user); } sqlSession.close(); }
多对多(跟一对多类似)
-
一、实现功能:根据角色表去找用户,中间要借助sys_user_role表
-
二、sql语句
select * from sys_role sr
left join sys_user_role sur
on sr.id = sur.userid
left join users u
on sur.userid = u.uid
5.6、嵌套查询
一对一(订单-用户)
OrderMapper.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="com.simon.dao.OrderMapper">
<resultMap id="orderMap1" type="order">
<id column="id" property="id"/>
<result column="ordertime" property="orderTime"/>
<result column="total" property="total"/>
<!--
select 代表要嵌套那个查询语句
column 表示要传递那个参数
fetchType="lazy" 局部懒加载
-->
<association fetchType="lazy" property="user" javaType="user" select="com.simon.dao.UserMapper.findUserById" column="uid">
</association>
</resultMap>
<select id="OrderToUser" resultMap="orderMap1">
select * from orders
</select>
<!--============================================-->
</mapper>
UserMapper.xml
<select id="findUserById" parameterType="_int" resultType="user">
select * from users where uid = #{uid}
</select>
一对多(用户到订单)
USerMapper.xml
<resultMap id="userMap1" type="user">
<id column="uid" property="id"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!--
select 代表要嵌套那个查询语句,通过全限定名
column 表示要传递那个参数 ,即通过那个属性相连接
一对多的话,property传的就是一对应的那个多,在一实体类中的变量名
如果对应的是多,那么一定要用collection
-->
<collection property="orders" ofType="order" select="com.simon.dao.OrderMapper.findOrderByUid" column="uid">
</collection>
</resultMap>
<select id="findAllUsersToOrder" resultMap="userMap1">
select * from users
</select>
OrderMapper.xml
<select id="findOrderByUid" parameterType="_int" resultType="order">
select * from orders where uid = #{uid}
</select>
多对多(用户对应角色)
UserMapper.xml
<resultMap id="userMap2" type="user">
<id column="uid" property="id"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!--
select 代表要嵌套那个查询语句,通过全限定名
column 表示要传递那个参数 ,即通过那个属性相连接
一对多的话,property传的就是一对应的那个多,在一实体类中的变量名
如果对应的是多,那么一定要用collection
-->
<collection property="roles" ofType="role" select="com.simon.dao.RoleMapper.UserToRoleByUserId" column="uid">
</collection>
</resultMap>
<select id="UserToRole" resultMap="userMap2">
select * from users
</select>
RoleMapper.xml
<select id="UserToRoleByUserId" parameterType="_int" resultType="role">
select * from sys_role sr, sys_user_role sur
where sr.id = sur.roleid and sur.userid = #{uid}
</select>
小结
一对一配置:使用+做配置,通过column条件,执行select查询 ,javaType
一对多配置:使用+做配置,通过column条件,执行select查询 ,ofType
多对多配置:使用+做配置,通过column条件,执行select查询 ,ofType
优点:简化多表查询操作
缺点:执行多次sql语句,浪费数据库性能
六、缓存
6.1一级缓存
6.2二级缓存
七、注解开发
小结
注解开发和xml配置优劣分析
1.注解开发和xml配置相比,从开发效率来说,注解编写更简单,效率更高。
2.从可维护性来说,注解如果要修改,必须修改源码,会导致维护成本增加。xml维护性更强。