mybatis学习笔记
什么是mybatis
- MyBatis 是一款优秀的持久层框架。
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
mybatis的优点
- sql和代码分离,提高了可维护性
- 提供映射标签,支持对象和数据库的字段关系映射
- 提供xml标签,支持动态sql语句
- mybatis可以简化jdbc的代码,同时可以让sql语句任意拼接。
mybatis的架构
CRUD(增删改查)
insert
<insert id="insert" parameterType="com.feng.pojo.User" >
insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd});
</insert>
id是DAo层对应的方法。parameter是参数类型
update
<update id="update" parameterType="com.feng.pojo.User">
update mybatis.user set name = #{name},pwd = #{pwd} where id=#{id};
</update>
delete
<delete id="delete" parameterType="int">
delete from mybatis.user where id = #{id};
</delete>
select
<select id="getUserList" resultType="com.feng.pojo.User">
select * from mybatis.user;
</select>
注意
<mapper namespace="">
<!--namespace根据自己需要创建的的mapper的路径和名称填写-->
</mapper>
这个namespace里面的是dao层下面对应的接口名
增删改需要提交事务,查询不用,
但如果
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(“true”);
}
该方法里面加了true,则不用写提交事务操作。
Map和模糊查询
万能的map
public interface UserMapper {
//万能的map
int insert2(Map<String,Object>map);
}
<insert id="insert2" parameterType="map" >
insert into mybatis.user(id, name, pwd) values
(#{Id},#{userName},#{password});
</insert>
使用了map,字段名可以不用对应,可以自己任意取名,但后面引用要使用自己取的
名字,而且可以插入自己想插入的字段,不用将所有字段写出,但是没用map的话不
行,名字也必须和数据库字段对应,不能修改。
**注意**
如果方法中有多个参数,需要使用到map或者使用@Param注解
模糊查询
第一种方式(推荐):
<select id="getUser" resultType="com.feng.pojo.User" parameterType="int">
select * from mybatis.user
where name like "%"#{value}"%";
</select>
第二种:
public class UserDaoTest {
@Test
public void test()
{
//第一步,获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//第二步,执行sql,方式一,getMapper
UserMapper userDao = sqlSession.getMapper(UserMapper.class);
List<User> users = userDao.getUserList("%李%");
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
}
配置解析
1.核心配置文件
mybatis-config.xml
属性(properties)
第一种直接写:
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=false&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="131556"/>
</dataSource>
第二种,引入外部配置条件
外部配置属性:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=false&characterEncoding=UTF-8
username=root
password=131556
引用
<!--引入外部配置条件-->
<properties resource="db.properties"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
<!--给实体类取别名-->
第一种是别名为User
<!--方法一-->
<!-- <typeAliases>-->
<!-- <typeAlias type="com.feng.pojo.User" alias="User"/>-->
<!-- </typeAliases>-->
第二种是一个包下面的所有文件都有别名,这个别名就是他们文件名的小写
<!--方法二-->
<typeAliases>
<package name="com.feng.pojo"/>
</typeAliases>
映射器(mappers)
我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 ,或类名和包名等。例如:
1.每一个mapper的.xml文件都需要到核心文件中去注册(mybatis-config.xml,操作就按照下面就可以实现)
2.接口和他的mapper配置文件必须同名
3.接口和他的配置文件必须在同一包下面
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="com/feng/Dao/UserMapper.xml"/>
</mappers>
注意上面的方法是"/"而下面的方法是".",同时上面那种方法有文件后缀名,
下面的则没有
<!-- 使用扫描包进行注入绑定-->
<mappers>
<mapper class="com.feng.Dao.UserMapper"/>
</mappers>
生命周期和作用域
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder
- 一旦创建了 SqlSessionFactory,就不再需要它了
- 局部变量
SqlSessionFactory
- 可以理解为数据库连接池
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在
SqlSession
- 连接到连接池的一个请求
- SqlSession 的实例不是线程安全的,因此是不能被共享的
- 每个线程都应该有它自己的 SqlSession 实例
- 用完后关闭,防止资源占用
ResultMap结果集映射
解决属性名和字段名不一致的问题
<!--namespace=绑定一个Dao/Mapper接口-->
<mapper namespace="com.feng.Dao.UserMapper" >
<select id="getUser" resultMap="UserMap" parameterType="int">
select * from mybatis.user where id = #{id};
</select>
<!--结果集映射-->
<resultMap id="UserMap" type="User">
<!--column是数据库中的字段,property是实体类的属性-->
<!-- <result column="id" property="id"/>-->
<!-- <result column="name" property="name"/>-->
<result column="pwd" property="password"/>
</resultMap>
</mapper>
日志
ybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Limit实现分页
<select id="getUsersByLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user limit #{startIndex},#{pageSize};
</select>
@Test
public void getUsersByLimitTest()
{
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
HashMap<String,Integer> map = new HashMap<String, Integer>();
map.put("startIndex",1);
map.put("pageSize",2);
List<User> users = userMapper.getUsersByLimit(map);
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
使用注解开发
@Select("select * from user")
List<User> getUsers();
可以不需要mapper的配置文件
@Insert("insert into user(id,name,pwd)values(#{id},#{name},#{password})")
int insert(User user);
@Param()注解
- 基本类型的参数或String类型,需要加上
- 引用类型不用加
- 多个参数需要使用
- SQL中的引用名是@Param()里面定义的
Lombok的使用
@Data
省去get和set的方法
@AllArgsConstructor
省去有参构造方法
@NoArgsConstructor
省去无参构造方法
@ToString
省去输出格式方法
多对一
多个学生关联一个老师(对学生而言)
@Data
public class Student {
private int id;
private String name;
//学生关联一个老师
private Teacher teacher;
}
<select id="getStudents2" resultMap="student_teacher2">
select s.id sid,s.name sname,t.name tname
from mybatis.student s,mybatis.teacher t
where s.tid = t.id;
</select>
<resultMap id="student_teacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
一对多
集合:
一个老师对应多个学生(对老师而言)
@Data
public class Teacher {
private int id;
private String name;
//一个老师有多个学生
private List<Student> students;
}
<select id="getStudents" resultMap="teacher_student">
select s.id sid,s.name sname,t.id tid,t.name tname
from mybatis.teacher t,mybatis.student s
where s.tid = t.id and t.id = #{tid};
</select>
<resultMap id="teacher_student" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--复杂的属性需要特殊处理-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
动态SQL
动态SQL指的是根据不同的条件生成不同的 SQL语句
IF语句
<select id="queryBlog" parameterType="map" resultType="blog">
select * from mybatis.blog where 1= 1
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
WHERE标签可以去除第一个的and
<select id="queryBlog" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
SET标签
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title != null ">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id};
</update>
SQL标签
1.使用sql标签会抽取公共的部分
<sql id="select">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
2.在需要的地方引用include标签即可
<select id="queryBlog" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<include refid="select">
</include>
</where>
</select>
foreach方法
动态 SQL 的另一个常见使用场景是对集合进行遍历
<!--
select * from blog where 1=1 and(id=1 or id=2 or id=3)
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<foreach collection="ids" item="id" open="(" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
choose标签
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。
执行一个,其他不会被执行
<select id="queryBlogChoose" resultType="blog" parameterType="map">
select * from mybatis.blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
缓存简介
1.什么是缓存
- 存在内存中的临时数据
- 将用户经常查询的数据放在缓存中,用户 不用每次去数据库文件提取数据,提高查询效率,解决高并发问题
2.为什么要用缓存
- 减少和数据库交互次数,提高效率,减少系统开销
3.什么样的数据可以用缓存
- 经常查询且不轻易改变的数据
mybatis缓存
- mybatis系统默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下只有一级缓存开启,(sqlsession级别的缓存,本地缓存)
- 二级缓存需要手动开启和配置,是namespace级别的缓存
- 我们通过实现cache接口自定义二级缓存
- 一级缓存的会话关闭了,一级缓存的数据会保留到二级缓存中
<!--在当前的Mapper.xml中开启二级缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
<select id="selectUserById" resultType="user" useCache="true">
select * from mybatis.user where id = #{uid};
</select>