Mybatis
Mybatis基础
基础知识
框架:开发的半成品,提高效率
ORM:object Relation Mapping :对象关系映射
表:类
数据:类的对象
字段:属性
Mybatis框架:
1、持久层框架,就是改了数据就会自动保存 封装了原始的jdbc操作
2、mybatis支持xml和注解两种方式配置sql
3、支持ORM思想封装sql结果
基操
1、创建实体类、数据库和表、导入响应的包、环境搭建好
2、映射文件里面配置sql语句
3、核心配置文件MybatisConfig.xml文件 连接数据库 、加载映射文件、起别名、日志配置、简化包里面的类路径
4、创建测试类 curd操作起来
Test类思路:
1、 加载核心配置文件
找到核心配置文件 核心配置文件以及帮我们处理了重要的连接数据库和加载映射文件这些操作
得到一个输入流对象
2 、获取SqlSessionFactory工厂对象
这个上代码: new SqlSessionFactoryBuilder().build() 是用来下一步获取SqlSession对象的
3、 通过SqlSessionFactory工厂对象获取SqlSession核心对象
这个就类似jdbc基操中的获取连接对象 可以执行sql语句、管理事务、接口代理
管理事务 默认是不提交的,传入参数为true或者在操作curd之后调用commit方法就可以提交事务,不然数据库了的数据是不会改变滴。
4 、执行操作获取结****果
namespace里面的参数.方法名 这就可以执行映射文件中的sql语句了
5 、打印结果
6、 释放资源
映射文件介绍
数据和对象的映射 写sql语句
<mapper namespace="StudentMapper">
<select id="findAll" resultType="com.itheima.domain.Student" paprameter="输入的数据类型">
select * from student
</select>
</mapper>
namepace:名称空间
id:代表这条select的唯一标识 就是想象成方法
resultType:输出的数据类型
paprameter:输入的数据类型
核心配置文件
连接数据库 、加载映射文件、起别名、日志配置、简化包里面的类路径
这里面的配置一些信息 标签会有顺序 不用刻意记 一个一个加 红的你就换个位置不红就对了
基本走向:Resource类加载核心配置文件得到一个输入流------new SqlsessionFactoryBuilder().build(输入流)得到工厂去创建sqlsession对象-----sqlsession对象加载映射文件中的sql语句—处理结果—释放资源
异常可能原因
核心数据库中数据库相关信息不对
namespace名字以及方法和sqlsession.selectList(“参数”)的参数不一样
核心配置文件中没有加载映射文件资源 注意:只能加载你需要的映射文件 多了其他的不行,少了你需要的也不行
测试成功 数据库内容没有改变 没有提交事务
mybatis集成log4j日志
步骤
1、导包
2、配置文件放到src里面
3、在核心配置文件中设置日志对象
<settings>
<!--配置日志管理信息-->
<setting name="logImpl" value="LOG4J"/>
</settings>
Mybatis提升
接口代理方式
就是sqlsession加载映射文件换成加载接口这个类文件
映射文件和接口的对应关系
接口的全类名=映射文件的namespace的值
接口的方法名=映射文件的id值
输出和输入类型 这个好理解
动态sql
if和forEach
使用场景:筛选 搜索
直接上代码
if
<!--多条件查询-->
<select id="selectCondition" resultType="student" parameterType="student">
select * from student
<where>
<!--test="" 是判断条件,如果使用where标签,SQL中多余的and会被自动舍弃-->
<if test="id != null">
and id=#{id}
</if>
<if test="name != null and name !='' ">
and name=#{name}
</if>
<if test="age != null">
and age=#{age}
</if>
</where>
</select>
forEach
<select id="selectByIds" resultType="Student" parameterType="list">
select * from student
<where>
<foreach collection="list" item="id" open=" id in (" separator="," close=")">
#{id}
</foreach>
</where>
</select>
注意: select * from student 后面别加 ; 这个表示select语句结束的意思 后面的就拼接不上咯
抽取代码块
分页插件
使用步骤:
1、导包 有两个
2、核心配置文件配置src下面
<!--集成PageHelper分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3、测试文件中
PageHelper.startPage(1,3); 开启分页设置页数和每条页数
然后可以得到这个分页对象
PageInfo info=new PageInfo<>(list);
里面有很对方法可以调用
xml和注解的单表以及多表操作
xml
单表:
curd的基操咯
多表
有一对一和一对多和多对多
第一种多表查询方式:
一对一:
一对一关系 就直接查询了 因为两个实体个类中都是展示直接的属性
需要用到resultmap、association 这个不一样的标签
例子:
<mapper namespace="com.itheima.mapper.OneToOneMapper">
<!--配置一对一映射关系
id="oneToOne":表示resultMap的唯一标识,再select标签中使用
type="card"表示最终要封装的数据类型
-->
<resultMap id="oneToOne" type="card">
<!--id标签表示映射主键信息,column="id"表示id列,property="id"表示id属性-->
<id column="id" property="id"/>
<!--result标签表示映射非主键信息-->
<result column="number" property="number"/>
<!--配置一对一关系
property="p" 表示card的对象属性名称
javaType="person" 表示对象属性的类型
-->
<association property="p" javaType="person">
<id column="pid" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
</association>
</resultMap>
<!--一对一:查询所有card信息,包括对应的person信息
resultType:表示封装查询结果的类型,会自动根据列名和对象的属性名自动封装,但是一对一关系中的person对象
属性无法封装,那么需要我们手动映射封装查询结果,此时就不能再使用resultType,改用resultMap
-->
<select id="findAll" resultMap="oneToOne">
select c.*,p.name,p.age from card c,person p where c.pid=p.id
</select>
</mapper>
一对多和多对多一样
collection标签使用
<resultMap id="oneToMany" type="Classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<!--将剩下的查询结果映射到students中,映射集合中的对象,ofType=""表示集合中的对象类型-->
<collection property="students" javaType="list" ofType="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
</collection>
</resultMap>
<select id="findAll" resultMap="oneToMany">
select c.id cid,c.NAME cname,s.id sid,s.NAME sname,s.age sage from classes c,student s where c.id=s.cid
</select>
这样显得你的sql语句写到一起了
我们可以将多表查询拆分成多次单表查询
改装:
collection、association里面的标签有一个select的属性可以参数写到另一个接口的全类名
代码例子演示:
<?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.itheima.relation.mapper.OneToOneMapper">
<!--resultMap手动映射,配置多表关系
autoMapping="true" :表示自动映射,字段名和属性名一样就可以自动映射,
如果不一样就手动映射
-->
<resultMap id="oneToOne" type="card" autoMapping="true">
<!--映射主键id-->
<!--<id column="id" property="id" javaType="int"/>-->
<!--映射普通字段number-->
<!--<result column="number" property="number" javaType="string"/>-->
<!--配置一对一关系
需求:根据card的pid查询对应的person信息,并且封装到card对象的p属性中
property="p" :要封装的对象名称,也就是属性名
javaType="person":属性类型,可以省略不写
column="pid" :根据pid自动去查询person信息
select="com.itheima.relation.mapper.PersonMapper.findById" :根据pid查询person信息要执行的方法
-->
<association property="p"
javaType="person"
column="pid"
select="com.itheima.relation.mapper.PersonMapper.findById"/>
</resultMap>
<!--需求:查询card信息以及对应的person信息-->
<select id="findAll" resultMap="oneToOne">
select * from card
</select>
</mapper>
select里面的参数对应的接口
public interface PersonMapper {
//根据id查询person信息
Person findById(Integer id);
}
一个映射文件对应一个接口
<?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.itheima.relation.mapper.PersonMapper">
<!--根据id查询person信息 Person findById(Integer id);-->
<select id="findById" parameterType="integer" resultType="person">
select * from person where id=#{id}
</select>
</mapper>
一对多和多对多都是一样的没什么区别 又是那个collection、association标签不一样而已
思路走向:
测试类里面的基操-----然后先加载第一个映射文件到了----然后加载第二个配置文件—又是基操
常见异常
核心配置文件里面需要写接口的全类名 而且是两个接口
映射文件和接口的四个对应关系错误
数据库相关信息错误
返回值错误----这个就要看你接口的返回值了
表之间的关系写错了数据出错
反正就是那基本操作,看异常处理就好了
注解方式:
注解
使用注解方式就可以不用写配置文件了
单表
@Select(“sql语句”)
@Insert(“sql语句”)
@Update(“sql语句”)
@Delete(“sql语句”)
多表
用到@Results、@Result、@One、@Many注解
写一个一对一的例子吧 一对多和多对多就是one和manyDe 区别
public interface OneToOneMapper {
//需求:查询所有身份证以及对应的person信息
@Results(id="oneToOneResult", //@Results注解相当于 <resultMap>...</resultMap>标签
value = {
//相当于<id column="id" property="id"/>
@Result(id = true,column = "id",property ="id" ),
//相当于<result column="number" property="number"/>
@Result(column = "number",property ="number" ),
//配置一对一关系
@Result(column = "pid", //pid表示调用PersonMapper.findById方法传递的参数
property = "p", //表示调用PersonMapper.findById方法返回的Person对象赋值给Card的p属性
one=@One(select="com.itheima.muti.mapper.PersonMapper.findById")) //配置一对一
}
)
@Select("select * from card")
public abstract List<Card> findAll();
}
PersonMapper对应的接口
public interface PersonMapper {
@Select("select * from person where id=#{id}")
public Person findById(Integer id);
}
格式不一样 思路差不多 @Result里面的标签表示什么注意一下就好了 异常看着解决 都是差不多的一个流程
动态SQL:推荐使用脚本的方式
@Select(在script标签里面写动态sql的代码)
public List selectCondition(Student stu);
mybatis里面的${}和#{}的区别
和那两个执行sql语句对象一样
${} Statement对象 会被注入攻击 不表示占位符 可以拼接
#{} parameterStatement对象 不会被注入攻击 表示占位符