MyBatis学习
什么是mybatis?
Mybatis是一个半自动的ORM持久层框架,内部封装了JDBC。作为开发者只需要关注sql语句本身。Mybatis是通过xml或注解的方式将需要执行的各种statement配置起来。通过Java对象和statement中的sql动态参数映射生成最终执行的sql语句,最终由Mabtais框架执行sql并将结果映射为Java对象并返回。MyBatis 支持定制化 SQL、存储过程以及高级映射。MyBatis 是可以双向映射的,可以将数据集映射为Java对象,也可以将Java对象映射为数据库中的记录。
使用mybatis框架
mybatis框架需要用xml文件来配置其信息
框架jar包地址链接:https://pan.baidu.com/s/1T-yuDMstY_P1DL-gjkuf0g
提取码:0000
注意,需要sql驱动包(mysql为例),驱动包在jdbc博客中可以找到,还要注意版本匹配问题
<!--mybatis.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>
<!-- jdbc配置信息-->
<properties resource="jdbc.properties"></properties>
<!-- 打印输出日志信息,需要导入log4j包-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--给实体类配置别名-->
<typeAliases>
<!--给指定类配置别名,在mapper返回中可以通过别名返回结果集到指定的实体类中-->
<typeAlias type="com.study.entity.Student" alias="student"></typeAlias>
<!--包下所有类的别名就是当前类名 类名首字母小写-->
<package name="com.study.entity"/>
</typeAliases>
<!--default属性指向使用哪个连接-->
<environments default="mysql">
<!--mysql数据库的连接-->
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<!--底层使用连接池连接数据库-->
<dataSource type="POOLED">
<!--连接数据库需要的配置信息 -->
<!-- 配置信息解耦合存储在jdbc.properties中,通过properties标签配置文件路径-->
<property name="driver" value="${m_driver}"/>
<property name="url" value="${m_url}"/>
<property name="password" value="${m_password}"/>
<property name="username" value="${m_username}"/>
</dataSource>
</environment>
<!--oracle数据库的连接-->
<environment id="oracle">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment>
</environments>
<mappers>
<!--resource书写的是xml所在目录,扫描mapper.xml文件进行数据库操作-->
<mapper resource="com/study/mapper/StudentMapper.xml"></mapper>
<!-- 扫描包下所有mapper.xml-->
<package name="com.study.mapper"/>
</mappers>
</configuration>
配置文件写好,接下来开始写mapper.xml
<!--mapper的约束-->
<?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命名空间,java代码通过此属性调用mapper中的某个查询-->
<mapper namespace="flower">
<!-- id属性,是java代码中调用的方法,resultType属性是返回的实体类类型,java中用Object接收-->
<select id="selectAll" resultType="flower">
select * from flower
</select>
<!--传入对象为实体类 parameterType指定传入的类型(可以省略),使用#{}来获取传入的对象属性,{}内写实体类的属性名-->
<select id="selectOne3" resultType="flower" parameterType="flower">
select * from flower where id=#{id} and name=#{name}
</select>
<select id="selectOne4" resultType="flower" parameterType="map">
<!--{}内的是key键名-->
select * from flower where id=#{id} and name=#{name}
<!--#底层使用占位符? $底层使用的是拼接 相当于statement-->
</select>
<!--增删改操作,只是标签和sql语句不同,其他一致-->
<insert id="insert" parameterType="flower">
insert into flower values(default,#{name},#{price},#{production})
</insert>
<update id="update" parameterType="flower">
update flower set name=#{name},price=#{price} where id=#{id}
</update>
<delete id="delete">
delete from flower where id=#{param1}
</delete>
</mapper>
下面来写对应的调用mapper的java
步骤和jdbc差不多,需要获取到SqlSession来进行操作
public class TestA {
public static void main(String[] args){
SqlSession session=null;
try {
//解析mybatis.xml
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
//获得session工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象
session=factory.openSession();
//参数对应mapper命名空间和增删改查的对应id
Object o = session.selectOne("flower.selectAll");//返回值会返回对应的mapper文件resultType属性的类型
//参数传递传入对象
Flower flower=new Flower();
flower.setId(1);
flower.setName("玫瑰");
Flower o = session.selectOne("flower", flower);
//参数传递三 map集合
Map<String,Object> map=new HashMap<>();
map.put("id",1);
map.put("name","玫瑰");
Object om= session.selectOne("flower", map);
System.out.println(om);
} catch (Exception e){
e.printStackTrace();
}finally {
//关闭sqlSession
if (session!=null){
session.close();
}
}
}
SqlSession的其他方法大同小异可查看api
注意事项:添加、删除、修改操作写好了必须提交
SqlSession.commit();
factory.openSession(true);
parameterType类型可以省略
封装SqlSession
将重复的获取sqlSession的操作封装起来
public class DBUtil {
private static SqlSessionFactory factory=null;
//使用ThreadLocal来对SqlSession进行管理
//此类会在同一个线程中使用同一个SqlSession
private static ThreadLocal<SqlSession> tl=new ThreadLocal<>();
//程序一加载就初始化所有需要的类
static {
InputStream inputStream=null;
try {
inputStream= Resources.getResourceAsStream("mybatis.xml");
factory=new SqlSessionFactoryBuilder().build(inputStream);
}catch (Exception e){
e.printStackTrace();
}finally {
if (inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static SqlSession getSqlSession(){
//获得sqlSession对象
SqlSession session = tl.get();
if (session==null){
session= factory.openSession();
//把创建好的session对象放入threadLocal
tl.set(session);
}
return tl.get();
//自动提交
//return factory.openSession(true);
}
public static void closeAll(){
SqlSession session = tl.get();
if (session!=null){
session.close();
}
}
}
为什么使用ThreadLocal管理可以查看此帖子
链接:https://blog.csdn.net/qq_16696457/article/details/108917103
使用mapper接口
mapper的接口要和其xml文件名称一致,并且放在同一个包下
//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.study.mapper.FlowerMapper1">
<!--id名称必须和接口方法名称一致-->
<select id="selectAll" resultType="flower">
select * from flower
</select>
<!--对于有参数的使用param1等进行传参,按照参数顺序进行排序-->
<select id="selectAll" resultType="flower">
select * from flower where id=#{param1} and name=#{param2}
</select>
</mapper>
//接口
public interface FlowerMapper1 {
List<Flower> selectAll();
//参数类型可以全是String类型,mysql中字符类型可以查询所有类型数据
List<Flower> selectAll(String id,String name);
}
mybatis.xml文件中需要配置扫描标签
//java调用
public class TestMapper4 {
public static void main(String[] args) {
SqlSession session=null;
try {
//解析mybatis.xml
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
//获得session工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象
session=factory.openSession();
//接口类对象
FlowerMapper1 mapper = session.getMapper(FlowerMapper1.class);
List<Flower> flowers = mapper.selectAll();
System.out.println(flowers);
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭sqlSession
if (session==null){
session.close();
}
}
}
}
OGNL表达式
通过特定标签来进行特殊的查询
<!--where标签-->
<select id="selectMore2" resultType="flower">
select * from flower
<!--OGNL表达式-->
<!--where标签作用,会自动地增加where关键字,并且会把多余的第一个and去掉-->
<where>
<!--if标签 ,进行判断如果为true则添加标签内表达式-->
<if test="param1!=null and param1!=''">
name=#{param1}
</if>
<if test="param2!=null and param2!=''">
and production=#{param2}
</if>
</where>
</select>
<!--set标签-->
<update id="update">
update flower
<!--set 会自动增加set关键字,并且去除最后一个逗号-->
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="production!=null and production!=''">
production=#{production}
</if>
</set>
where id=#{id}
</update>
<!--trim标签-->
<update id="update">
update flower
<!--
prefix:添加前缀
prefixOverrides:去除前缀
suffixOverrides:去除后缀
suffix:添加后缀
-->
<trim prefix="set" suffixOverrides=",">
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="production!=null and production!=''">
production=#{production}
</if>
</trim>
where id=#{id}
</update>
<!--choose标签-->
<select id="selectMore3" resultType="flower">
select * from flower
<!--OGNL表达式-->
<!--where标签作用,会自动地增加where关键字,并且会把多余的第一个and去掉-->
<where>
<choose>
<when test="param1!=null and param1!=''">
name=#{param1}
</when>
<when test="param2!=null and param2!=''">
and production=#{param2}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
<!--foreach标签,用来进行模糊查询-->
<select id="selectMore" resultType="flower">
select * from flower where id in
<!--collection集合类型,open separator close代表前缀后缀和分割 item是集合中每个数据-->
<foreach collection="list" open="(" separator="," close=")" item="it">
#{it}
</foreach>
</select>
//java代码
public class TestMapper4 {
public static void main(String[] args) {
SqlSession session=null;
try {
//解析mybatis.xml
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
//获得session工厂
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象
session=factory.openSession();
FlowerMapper4 mapper = session.getMapper(FlowerMapper4.class);
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
List<Flower> flowers = mapper.selectMore(list);
System.out.println(flowers);
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭sqlSession
if (session==null){
session.close();
}
}
}
}
<!--bind标签,用来进行模糊查询-->
<select id="selectMore" resultType="flower">
select * from flower
<where>
<if test="param1!=null and param1!=''">
<!--bind用于模糊查询-->
<bind name="pa" value="'%'+param1+'%'" ></bind>
name like #{pa}
</if>
<!--bind标签都可以实现占位符(不会有sql注入) $是进行拼接-->
<if test="param2!=null and param2!=''">
and production like '%${param2}%'
</if>
</where>
</select>
resultMap
resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。适合用于多表查询
详细使用参考链接:https://www.cnblogs.com/kenhome/p/7764398.html
<select id="selectAll" resultMap="rm3">
select * from student join clazz on student.clazzno=clazz.clazz
</select>
//id相互对应,type映射的实体类对象
<resultMap id="rm3" type="student">
//column查询出来的列字段 property映射到实体类的属性
<id column="sid" property="sid"></id>
<result column="sname" property="sname"></result>
<result column="clazzno" property="clazzno"></result>
//property实体类中的属性 javaType实体类中关联的实体类属性
<association property="clazz" javaType="clazz">
<id column="clazz" property="clazz"></id>
<result column="cname" property="cname"></result>
</association>
</resultMap>
resultMap嵌套
<select id="selectAll" resultMap="rm1">
select * from student
</select>
<resultMap id="rm1" type="student">
<!--column:数据库的列名 property:实体的属性名-->
<id column="sid" property="sid"></id>
<result column="sname" property="sname"></result>
<result column="clazzno" property="clazzno"></result>
<!--
select:执行哪一个方法,执行mapper接口的方法,将结果集需要的列值传入指定的对象
column:希望查询的哪一列作为参数进行传递
javaType:返回值类型
property:把返回的结果赋值给对象中哪一个属性
-->
<association select="com.study.mapper.ClazzMapper.selectOne" column="clazzno" javaType="clazz" property="clazz"></association>
</resultMap>
collection标签
<select id="selectOne" resultMap="rm2">
select * from clazz where clazz=#{param1}
</select>
<resultMap id="rm2" type="clazz">
<id column="clazz" property="clazz"></id>
<result column="cname" property="cname"></result>
<!--ofType返回集合泛型-->
<collection select="" property="students" ofType="student" column="clazz"></collection>
<!-- 注意:<collection>标签中的column:要传递给select查询语句的参数,如果传递多个参数,格式为column= ” {参数名1=表字段1,参数名2=表字段2} ;-->
</resultMap>
mybatis获取自增主键
<insert id="insert" parameterType="flower" useGeneratedKeys="true">
insert into flower values(default,#{name},#{price},#{production})
</insert>
<!--接口方法传入的参数会接收自增主键的返回,只需要从方法参数中获取即可-->
缓存
<!--启动二级缓存-->
<cache readOnly="true"></cache>
缓存分为一级二级
一级:sqlsession缓存
二级:factory缓存
sqlSession(先取db,其次从一级缓存取出,当关闭sqlSession时close或者提交时 commit ,一级缓存将会刷入二级缓存)
|
二级缓存 factory
|
一级缓存 sqlSession
|
DB数据库