Mybatis
一款优秀的基于Java的持久层框架,方便使用者对数据库进行操作;
作用:就是对关系型数据库的进行操作的基础框架;
ORM(Objects Relation Mapping) :对象关系映射;
数据库表结构实体类
表字段成员变量(属性)
标的一行记录==创建的一个对象
基本使用步骤
1、导入jar包
2、配置核心配置文件
<?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>
<settings>
<!--控制台输出sql语句,会返回影响的详细数据-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 整个实体包起别名,其中的别名就是类名-->
<typeAliases>
<package name="com.itcast.entity"/>
</typeAliases>
<!--环境配置选择-->
<environments default="development">
<!--id代表可以被选择的环境配置;可以配置多个环境标签进行选择-->
<environment id="development">
<!--事务管理器-->
<transactionManager type="JDBC"/>
<!--数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3305/db1"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 加载映射配置文件 -->
<mapper resource="StuMapperConfig.xml"></mapper>
</mappers>
</configuration>
3、配置映射配置文件
<?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="StuMapperConfig">
<!--
id:表示接口中方法名
resultType:表示方法返回的数据类型,如果返回的是集合,这里指定集合中每个元素类型
select标签标签体就是SQL语句
parameterType参数类型,可以省略
-->
<select id="selectAll" resultType="com.itcast.entity.Student">
select * from student
</select>
<!-- 获取参数用#{参数名};一般建议参数名与输入参数名相同 -->
<select id="selectById" resultType="com.itcast.entity.Student" parameterType="Integer">
select * from student where id = #{id}
</select>
<!-- 插入一条数据,修改删除与之类似,主标签修改为delete和update -->
<insert id="insertStu" parameterType="com.itcast.entity.Student">
insert into student values(#{id},#{name},#{age})
</insert>
</mapper>
4、创建实体类和表数据相对应
5、使用
//查询数据
@Test
public void test01() throws IOException {
//得到核心配置文件输入流;使用Resources.getResouceAsStream()能获的相同效果
InputStream is = Test01.class.getClassLoader().getResourceAsStream("MybatisConfig.xml");
//获取会话工厂对象
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
//获取会话对象;其中传入true,代表自动提交事务,否则代表手动提交事务
SqlSession sqlSession = build.openSession();
/*
//查询获得的结果封装到一个list集合中
List<Student> lists = sqlSession.selectList("StuMapperConfig.selectAll");
for (Student list : lists) {
System.out.println(list);
}*/
//查询获取一个单独的对象
Student stu = sqlSession.selectOne("StuMapperConfig.selectById", 3);
System.out.println(stu);
sqlSession.close();
is.close();
}
/*
插入一条记录;删除和修改一条数据与之类似
*/
@Test
public void test02() throws IOException {
InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = build.openSession(true);
Student stu = new Student(5, "赵六", 26);
//插入一个对象
int s = sqlSession.insert("StuMapperConfig.insertStu", stu);
System.out.println(s);
sqlSession.close();
is.close();
}
Mybatis核心配置文件
核心配置文件中的标签写入是需要顺序的;
<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>
点进configuration标签,可以看到dtd约束文档中内部标签顺序,需要按照此顺序写入(可以不写略过),否则报错;
properties
作用:加载properties文件,并在核心配置文件中使用;
属性:resource,获取properties资源路径;
<properties resource="pro.properties">
使用
<dataSource type="POOLED">
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</dataSource>
typeALiases
作用:用于给实体类起别名
属性:package,用于给整个包下所有类起别名,类名小写就是别名
typeAlias,用于单独给一个类起别名(type:类名;alias:别名)
某些java常用类(基础数据类型,String等)Mybatis已经自动起了别名;就是类名
<typeAliases>
<package name="com.itcast.entity"/>
</typeAliases>
settings
作用:引入LOG4J配置文件
<settings>
<setting name="logImpl" value="log4j"/>
</settings>
tip
idea中文件上点右键中的local history可以查看文件的修改记录;
大面积修改:选中要修改的字段,Ctrl+f之后Ctrl+r输入修改后的字段;
LOG4J配置文件
作用:输出代码执行的具体信息
# Global logging configuration
# 有四种模式;最详细debug->info->warn->error;
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
Mybatis传统方式中的三层架构
控制层:controller–>业务层:service–>持久层:dao
持久层写接口
/*
持久层接口
*/
public interface StudentMapper {
//查询全部
public abstract List<Student> selectAll();
//根据id查询
public abstract Student selectById(Integer id);
//新增数据
public abstract Integer insert(Student stu);
//修改数据
public abstract Integer update(Student stu);
//删除数据
public abstract Integer delete(Integer id);
}
业务层调用持久层
接口
public interface StudentService {
//查询全部
public abstract List<Student> selectAll();
//根据id查询
public abstract Student selectById(Integer id);
//新增数据
public abstract Integer insert(Student stu);
//修改数据
public abstract Integer update(Student stu);
//删除数据
public abstract Integer delete(Integer id);
}
实现
public class StudentServiceImpl implements StudentService {
private StudentMapper studentMapper;
public StudentServiceImpl() {
InputStream is = null;
SqlSession sqlSession = null;
try {
is = Resources.getResourceAsStream("MybatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
studentMapper = sqlSession.getMapper(StudentMapper.class);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<Student> selectAll() {
return studentMapper.selectAll();
}
@Override
public Student selectById(Integer id) {
return studentMapper.selectById(id);
}
@Override
public Integer insert(Student stu) {
return studentMapper.insert(stu);
}
@Override
public Integer update(Student stu) {
return studentMapper.update(stu);
}
@Override
public Integer delete(Integer id) {
return studentMapper.delete(id);
}
}
测试
private StudentServiceImpl studentService = new StudentServiceImpl();
@Test
public void test03(){
Student stu = new Student(10, "小明", 29);
Integer insert = studentService.insert(stu);
System.out.println(insert);
}
注意
1、其中的关系映射文件中的命名空间必须是持久层接口类的全限定类名(namespace);
2、在业务层中调用的getMapper()方法,使用动态代理的方式对传入接口中的方法进行了实现,简化了代码;
动态sql
标签:where、if、foreach、sql、include
作用:简化代码;增加可读性;
where:如果此标签内部有内容,则会在SQL语句后面加入where字段
if:判断是否符合条件,如果符合则将其中字段加入SQL语句
foreach:按照一定条件循环其内部sql语句
sql:设置一段sql语句,方便其他标签中插入使用
include:导入sql标签设置的sql语句
if、where
<select id="selectCondition" resultType="student" parameterType="student">
select * from student
<where>
<!-- 会自动省略第一个and -->
<if test="id != null">
and id=#{id}
</if>
<if test="name != null">
and name=#{name}
</if>
<if test="age != null">
and age=#{age}
</if>
</where>
</select>
foreach、where、include
<select id="selectByIds" resultType="student">
<include refid="sql"></include>
/* select * from student*/
<where>
<foreach collection="list" open="id in(" close=")" separator="," item="id">
#{id}
</foreach>
</where>
</select>
sql
一般用于抽取字段名(字段名太多时)·
<sql id="sql">
select * from student
</sql>
分页插件(PageHelper)
直接在业务层(现在是测试类)调用getMapper()前使
用即可;
1、导包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ArQqwFub-1592965759084)(C:\Users\computer\AppData\Local\Temp\1592382677751.png)]
2、核心配置文件中配置插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3、业务层使用
@Test
public void test07(){
PageHelper.startPage(0,2);//简单分页
List<Student> students = studentService.selectAll();
System.out.println(students);
PageInfo<Student> infos = new PageInfo(Students);//获取对象后,使用下述方法
}
在查出数据后,可以使用PageInfo类,来获取详细信息PageHelper:分页助手功能类。
startPage():设置分页参数
PageInfo:分页相关参数功能类。
getTotal():获取总条数
getPages():获取总页数
getPageNum():获取当前页
getPageSize():获取每页显示条数
getPrePage():获取上一页
getNextPage():获取下一页
isIsFirstPage():获取是否是第一页
isIsLastPage():获取是否是最后一页
MyBatis多表查询(配置文件方式)
一对一映射
映射配置文件的变化
ResultMap
配置表字段与实体类属性的映射关系;
相当于方法的返回值;
等同于resultType;
相当于一个转换器,具体属性在标签中的type指定;
内部标签
id:指定表中id属性(即主键属性);
result:其他的属性;
association:定义引用数据类型;
具体使用
<!--配置字段和实体对象属性的映射关系-->
<resultMap id="oneToOne" type="card">
<id column="cid" property="id" />
<result column="number" property="number" />
<!--
association:配置被包含对象的映射关系
property:被包含对象的变量名
javaType:被包含对象的数据类型
-->
<association property="p" javaType="person">
<id column="pid" property="id" />
<result column="name" property="name" />
<result column="age" property="age" />
</association>
</resultMap>
<select id="selectAll" resultMap="oneToOne">
SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id
</select>
一对多映射
内部标签中association换成了collection,其余基本相同;
使用;
<resultMap id="oneToMany" type="classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<!--
collection:配置被包含的集合对象映射关系
property:被包含对象的变量名
ofType:被包含对象的实际数据类型
-->
<collection property="students" ofType="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
</collection>
</resultMap>
<select id="selectAll" 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>
多对多映射
使用
<resultMap id="many" type="course">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<collection property="students" ofType="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
</collection>
</resultMap>
<select id="selectAllCourse" resultMap="many">
SELECT sc.sid,s.name sname,s.age sage,sc.cid,c.name cname FROM student s,course c,stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id
</select>
resultMap和resultType的区别
1、当实体类属性名称和表列名不相同时,需要使用resultMap;
2、当实体类属性中含有另一引用数据类型时,需要使用resultMap;
3、基本数据类型和String等可以直接使用resultType;
注解开发
在日常使用MyBatis开发中,也可以使用注解的方式进行数据库sql语句的操作(即放弃使用映射关系配置文件的方式操作数据库);
好处;可读性增加,代码量减少,方便开发;
简单使用注解开发
改变1、不配置关系映射文件,同时在核心配置文件中配置接口文件的路径
<!--配置映射关系-->
<mappers>
<package name="com.itheima.mapper"/>
</mappers>
改变2、在接口中的方法上加上相应注解
@Select
@insert
@Update
@Delete
//查询全部
@Select("SELECT * FROM student")
public abstract List<Student> selectAll();
//新增操作
@Insert("INSERT INTO student VALUES (#{id},#{name},#{age})")
public abstract Integer insert(Student stu);
//修改操作
@Update("UPDATE student SET name=#{name},age=#{age} WHERE id=#{id}")
public abstract Integer update(Student stu);
//删除操作
@Delete("DELETE FROM student WHERE id=#{id}")
public abstract Integer delete(Integer id);
其余操作不变;
详解注解开发
多表查询
封装结果需要使用注解@Results
一对一
使用
//查询全部
@Select("SELECT * FROM card")
@Results({
@Result(column = "id",property = "id"),
@Result(column = "number",property = "number"),
@Result(
property = "p", // 被包含对象的变量名
javaType = Person.class, // 被包含对象的实际数据类型(可以省略)
column = "pid", // 根据查询出的card表中的pid字段来查询person表
/*
one、@One 一对一固定写法
select属性:指定调用哪个接口中的哪个方法
*/
one = @One(select = "com.itheima.one_to_one.PersonMapper.selectById")
)
})
public abstract List<Card> selectAll();
PersonMapper表
其实可以将方法写在上述接口中,方便调用;
//根据id查询
@Select("SELECT * FROM person WHERE id=#{id}")
public abstract Person selectById(Integer id);
一对多
使用
//查询全部
@Select("SELECT * FROM classes")
@Results({
@Result(column = "id",property = "id"),
@Result(column = "name",property = "name"),
@Result(
property = "students", // 被包含对象的变量名
javaType = List.class, // 被包含对象的实际数据类型
column = "id", // 根据查询出的classes表的id字段来查询student表
/*
many、@Many 一对多查询的固定写法
select属性:指定调用哪个接口中的哪个查询方法
*/
many = @Many(select = "selectByCid")
)
})
public abstract List<Classes> selectAll();
//根据cid查询student表
@Select("SELECT * FROM student WHERE cid=#{cid}")
public abstract List<Student> selectByCid(Integer cid);
多对多
使用
//查询全部
@Select("SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id")
@Results({
@Result(column = "id",property = "id"),
@Result(column = "name",property = "name"),
@Result(column = "age",property = "age"),
@Result(
property = "courses", // 被包含对象的变量名
javaType = List.class, // 被包含对象的实际数据类型
column = "id", // 根据查询出student表的id来作为关联条件,去查询中间表和课程表
/*
many、@Many 一对多查询的固定写法
select属性:指定调用哪个接口中的哪个查询方法
*/
many = @Many(select = "selectBySid")
)
})
public abstract List<Student> selectAll();
//根据学生id查询所选课程
@Select("SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}")
public abstract List<Course> selectBySid(Integer id);
sql构建器使用
作用:用于生成sql语句,方便开发;
使用;
1、根据需求生成sql语句;
//定义方法,返回查询的sql语句
public String getSelectAll() {
return new SQL(){//匿名内部类
{//构造代码块
SELECT("*");
FROM("STUDENT");
}
}.toString();//通过该类的toString方法生成sql语句
}
2、接口调用
注解SelectProvider调用;(其余增删改类似)
属性:
type:调用哪个类,写入其字节码文件;
method:生成sql语句的方法名;
@SelectProvider(type = ReturnSql.class , method = "getSelectAll")
public abstract List<Student> selectAll();
3、测试
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> list = mapper.selectAll();
for (Student student : list) {
System.out.println(student);
}
sqlSession.close();
MyBatis整合工程
1、导包(mybatis+mysql)
2、核心配置文件
3、修改接口文件
Provider调用;(其余增删改类似)
属性:
type:调用哪个类,写入其字节码文件;
method:生成sql语句的方法名;
@SelectProvider(type = ReturnSql.class , method = "getSelectAll")
public abstract List<Student> selectAll();
3、测试
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> list = mapper.selectAll();
for (Student student : list) {
System.out.println(student);
}
sqlSession.close();
MyBatis整合工程
1、导包(mybatis+mysql)
2、核心配置文件
3、修改接口文件
4、修改service层(业务层)