JAVA后端框架--【Mybatis】
框架
框架就是对技术的封装,将基础的技术进行封装,让程序员快速使用,提高开发效率
java后端框架
mybatis
对jdbc进行封装
背景介绍
mybatis是apache下面的一个开源项目,名为ibatis,2010年开发团队转移到谷歌旗下,更名为mybatis
mybatis是一个优秀的数据持久性框架(dao层 数据访问层 数据持久性)
对jdbc进行封装,避免了jdbc中手动设置参数,手动映射结果的操作
mybatis将jdbc中接口进行封装,提供了它自己的类和接口实现。
mybatis可以使用xml配置和注解的方式,将数据库中记录自动映射到java对象中,
是一种orm实现(对象关系映射)将可以自动映射到对象中的这种框架,也称为orm框架
mybatis还提供了动态sql和数据缓存功能
mybatis搭建
1.创建mven项目
2.导入mybatis依赖的jar
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
3.创建一个全局的mybatis配置文件,配置数据库进行链接
<?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>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--为类配置别名-->
<typeAliases>
<package name="com.wph.mybatis.model"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/ssmdb?serverTimezone=Asia/Shanghai" />
<property name="username" value="root" />
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--注册映射文件-->
<mappers>
<mapper resource="Mappers/AdminMapper.xml"></mapper>
</mappers>
</configuration>
4.创建数据库,创建表
create database ssmdb
create table admin(
id int primary key auto_increment,
account varchar(10),
password varchar(10),
gender varchar(10)
)
5.创建一个访问接口,定义方法
package com.wph.mybatis.dao;
import com.wph.mybatis.model.Admin;
import org.apache.ibatis.annotations.Param;
public interface AdminDao {
Admin findAdminbyid(int id);
Admin findAdminbyAccount(String account);
Admin login(@Param("acc") String account,@Param("pwd") String password);
Admin login1(Admin admin);
void deleteadmin(int id);
void insert(Admin admin);
void update(Admin admin);
}
6.创建接口对应映射文件
<?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.wph.mybatis.dao.AdminDao">
<update id="update" parameterType="Admin">
update admin set account=#{account},password=#{password},gender=#{gender} where id=#{id}
</update>
<select id="findAdminbyid" parameterType="int" resultType="Admin">
select * from admin where id = #{id}
</select>
<select id="findAdminbyAccount" parameterType="String" resultType="Admin">
select * from admin where account = #{account}
</select>
<select id="login" resultType="Admin">
select * from admin where account=#{acc} and password =#{pwd}
</select>
<select id="login1" resultType="Admin">
select * from admin where account=#{account} and password =#{password}
</select>
<delete id="deleteadmin" parameterType="int">
delete from admin where id=#{id}
</delete>
<!--useGeneratedKeys="true" keyProperty="id" keyColumn="id"-->
<insert id="insert" parameterType="Admin" >
insert into admin(account,password,gender) values (#{account},#{password},#{gender})
</insert>
</mapper>
7.测试 MyBatis
读取配置文件 Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); 创建 SqlSessionFactory SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
创建 SqlSession SqlSession sqlSession = sessionFactory.openSession();
获得接口代理对象 sqlSession.getMapper(接口.class); sqlSession .close();
package com.wph.mybatis.Test;
import com.wph.mybatis.dao.AdminDao;
import com.wph.mybatis.model.Admin;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
public class test {
public static void main(String[] args) throws IOException {
//1.mybatis读取配置文件
Reader reader= Resources.getResourceAsReader("mabiatis.xml");
//2.创建SqlSeaaionFactory ,负责创建SqlSession对象
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
//3.创建SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//创建接口的代理对象
AdminDao adminDao =sqlSession.getMapper(AdminDao.class);
Admin admin=adminDao.findAdminbyid(1);//让代理对象帮我们调用映射文件与此接口中相同名称的方法
System.out.println(admin);
sqlSession.close();//关闭会话对象
}
}
关闭 API 接口说明 SqlSessionFactory 接口 使用 SqlSessionFactory 来创建 SqlSession,一旦创建 SqlSessionFactory 就 会在整个应用过程中始终存在。由于创建开销较大,所以没有理由去销毁再创建 它,一个应用运行中也不建议多次创建 SqlSessionFactory。 SqlSession 接口 Sqlsession 意味着创建与数据库链接会话,该接口中封装了对数据库操作的方 法,与数据库会话完成后关闭会话。
package com.wph.mybatis.Test;
import com.wph.mybatis.dao.AdminDao;
import com.wph.mybatis.model.Admin;
import com.wph.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class test3 {
/*
单元测试,程序员使用的测试方法,以方法为单位测试
使用junit组件实现单元测试
*/
@Test
public void insert(){
Admin admin=new Admin();
admin.setAccount("aaa");
admin.setPassword("123");
admin.setGender("男");
SqlSession sqlSession= MyBatisUtil.getSqlsession();
AdminDao adminDao=sqlSession.getMapper(AdminDao.class);
adminDao.insert(admin);
sqlSession.commit();//提交数据库事务,当我们的程序代码执行没有任何问题时,再向数据库发送提交事务操作,数据库真正执行
//sql,出现异常则不提交,新增,修改,删除完毕后,都需要手动提交事务
sqlSession.close();
/*
* 数据库事务:是数据库的一个管理机制,是对一次链接数据库过程的管理,
* 保证一次操作中,执行的多条sql,要么都成功执行,要么都不执行
* 转账: 链接到数据库
* 1.先从A账户捡钱sql11
* 其他代码逻辑(可能出现异常)
* 2.再向B账户加钱 sql2
* 提交事务 数据库才会真正的在数据库执行这一次操作中多条sql
* */
}
@Test
public void delete(){
SqlSession sqlSession= MyBatisUtil.getSqlsession();
AdminDao adminDao=sqlSession.getMapper(AdminDao.class);
adminDao.deleteadmin(1);
sqlSession.commit();
sqlSession.close();
}
@Test
public void update(){
Admin admin=new Admin();
admin.setAccount("ddd");
admin.setPassword("666");
admin.setGender("女");
admin.setId(1);
SqlSession sqlSession= MyBatisUtil.getSqlsession();
AdminDao adminDao=sqlSession.getMapper(AdminDao.class);
adminDao.update(admin);
}
}
数据库连接池
链接数据库每次访问数据库时候,创建一个Cinnection,用完关闭,但是访问量大了后,每次都要创建新的连接对象,用完关闭,比较耗时
使用数据库连接池,在池(集合)中事先创建一些链接对象,用完不销毁,还回到池中这样就减小频繁创建销毁链接对象。
package com.wph.mybatis.Test;
import com.wph.mybatis.dao.AdminDao;
import com.wph.mybatis.model.Admin;
import com.wph.mybatis.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
public class test2 {
public static void main(String[] args) {
//SqlSession是每次与数据库链接会话对象,用完关闭
SqlSession sqlSession= MyBatisUtil.getSqlsession();
AdminDao adminDao=sqlSession.getMapper(AdminDao.class);
adminDao.findAdminbyid(1);
Admin admin=adminDao.findAdminbyAccount("admin");
System.out.println(admin);
//Admin admin=adminDao.login("admin", "111");
//System.out.println(admin);
/*Admin admin1=new Admin();
admin1.setAccount("admin");
admin1.setPassword("111");
Admin admin2=adminDao.login1(admin1);*/
sqlSession.close();//关闭链接对象,如果使用数据库连接功能,本质上没有关闭,回到池中
}
}
增删改查
唯一标识" useGeneratedKeys="把新增加的主键赋值到自己定义的 keyProperty " keyProperty=“ 接收主键的属性 parameterType="参数类型">
insert into admin(account,password)values(#{account},#{password})
<!--useGeneratedKeys="true" keyProperty="id" keyColumn="id"-->
<insert id="insert" parameterType="Admin" >
insert into admin(account,password,gender) values (#{account},#{password},#{gender})
</insert>
修改 "唯一标识" parameterType=“参数类型">
<update id="update" parameterType="Admin">
update admin set account=#{account},password=#{password},gender=#{gender} where id=#{id}
</update>
update admin set account= #{account},password= #{password} where id= #{id}
删除 "唯一标识" parameterType="参数类型"> delete from admin where id= #{id}
<delete id="deleteadmin" parameterType="int">
delete from admin where id=#{id}
</delete>
查询 唯一标识" resultType="返回结果集类型"> select * from admin where id= #{id}
<resultMap id="adminMap" type="Admin">
<id column="adminid" property="id"></id>
<result column="account" property="account"></result>
</resultMap>
<select id="findadmin" resultMap="adminMap">
select id adminid ,account from admin
</select>
#{} 和${}区别
#{} 占位符,是经过预编译的,编译好 SQL 语句再取值,#方式能够防止 sql 注入
#{}:delete from admin where id=#{id}
结果: delete from admin where id = ?
${}会将将值以字符串形式拼接到 sql 语句,
${ }方式无法防止 Sql 注入 ${}: delete from admin where id=’${id}’
结果: delete from admin where id=’1’ 一般是#{ } 向 sql 传值使用, 而使用${ }向 sql 传列名
<select id="login1" resultType="Admin">
select * from admin where account=#{account} and password =#{password}
</select>
<select id="findbyid" parameterType="java.lang.String" resultType="java.lang.Integer">
select id from admin where account = ${account}
</select>
#{} 是占位符,是采用预编译方式向sql中传值,可以防止sql注入,如果我们往sql中传值,使用#{}
${} 是将内容直接拼接到sql语句中,一般不用于向sql中传值,一般用于向sql动态传递列名
区别:
底层实现不同
#{} 采用预编译方式,防止sql注入更加安全
${} 采用字符串拼接,直接将值拼接到sql中
使用场景不同
#{}一般用于向sql中列传值
${}一般用于向sql动态传递列 例如 排序时 order by 后面的列名是可以改变的
特殊处理定义 resultMap
(1). resutlMap 的 id 属性是 resutlMap 的唯一标识,本例中定义为 “adminResultMap”
(2). resutlMap 的 type 属性是映射的 POJO 类型
(3). id 标签映射主键,result 标签映射非主键
(4). property 设置对象属性名称,column 映射查询结果的列名称
多表关联处理结果集
resultMap 元素中 association , collection 元素. Collection 关联元素处理一对多关联
public class Student {
private int id;
private String name;
private int num;
private String gender;
private int majorid;
private Major major;
}
--------------------------------------
public class Major {
private int id;
private String name;
private List<Student> students;
}
-------------------------------------
<resultMap id="studentMap" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<!--映射关联数据 专业名称-->
<association property="major" javaType="Major">
<result column="mname" property="name"></result>
</association>
</resultMap>
<select id="findStudentbyid" resultMap="studentMap">
select s.id,s.num,s.name,s.gender,m.name mname
from student s inner join major m on s.majorid=m.id where s.id =#{id}
</select>
<select id="findStudents" resultMap="studentMap">
select s.id,s.num,s.name,s.gender,m.name mname
from student s inner join major m on s.majorid=m.id </select>
<resultMap id="majorMap" type="Major">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<collection property="students" javaType="list" ofType="Student">
<result column="num" property="num"></result>
<result column="sname" property="name"></result>
</collection>
</resultMap>
<select id="findmajorbyid" parameterType="int" resultMap="majorMap">
select m.id,m.name,s.num,s.name sname
from major m inner join student s on m.id =s.majorid where m.id=#{id}
</select>
<select id="findmajorall" parameterType="int" resultMap="majorMap">
select m.id,m.name,s.num,s.name sname
from major m inner join student s on m.id =s.majorid
</select>
嵌套查询
将一个多表关联查询拆分为多次查询,先查询主表数据,然后查询关联表数据.
(1). select:指定关联查询对象的 Mapper Statement ID 为 findDeptByID
(2). column="dept_id":关联查询时将 dept_id 列的值传入 findDeptByID, 并将 findDeptByID 查询的结果映射到 Emp 的 dept 属性中
(3).collection 和 association 都需要配置 select 和 column 属性,两者配置方法 相同
<!--
=============================================================
关联查询方式2:嵌套查询 先查询主表(学生表)
-->
<resultMap id="studentMap1" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<association property="major" javaType="Major" select="findmajorid" column="majorid"></association>
</resultMap>
<select id="findbuid" resultMap="studentMap1">
select id,num,name,gender,majorid from student where id=#{id} ;
</select>
<!--嵌套查询学生关联专业-->
<select id="findmajorid" resultType="Major">
select name from major where id=#{majorid}
</select>
<resultMap id="majorMap1" type="Major">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<collection property="students" javaType="list" ofType="Student" select="findStudents" column="id"></collection>
</resultMap>
<select id="findmajor" resultMap="majorMap1">
select id,name from major
</select>
<select id="findStudents" resultType="Student">
select num,name from student where majorid =#{id}
</select>
Mybatis 动态 SQL
MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。
如果你有使用 JDBC 或其他 相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么 的痛苦,确保不能忘了空格或在列表的最后省略逗号。
动态 SQL 可以彻底处理 这种痛苦。
MyBatis 中用于实现动态 SQL 的元素主要有:
If wheretrim set choose (when, otherwise) foreach
<?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.wph.mybatis.dao.TeacherDao">
<!--
动态sql中添加逻辑判断
可以在sql中添加逻辑判断
if test 属性条件成立 执行if 标签体,不成立就不执行
where 标签 当where标签 if 语句有条件成立时,就会动态添加where关键字,
还可以删除where后面紧跟着的关键字
-->
<!-- <select id="teachers" resultType="Teacher">
select * from teacher
<where>
<if test="num!=null">
num = #{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</where>
</select>-->
<select id="teachers" resultType="Teacher">
select * from teacher
<trim prefix="where" prefixOverrides="and|or">
<choose>
<when test="name!=null">
name =#{name}
</when>
<otherwise>
name='王老师'
</otherwise>
</choose>
</trim>
</select>
<select id="findTeacher" resultType="Teacher">
select
<foreach item="col" collection="list" separator=",">
${col}
</foreach>
from teacher
</select>
<update id="updateTeacher" parameterType="Teacher">
update teacher
<set>
<if test="num!=null">
num=#{num},
</if>
<if test="name!=null">
name=#{name},
</if>
<if test="gender!=null">
gender =#{gender}
</if>
</set>
where id=#{id}
</update>
<delete id="deleteTeacher">
delete from teacher where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
${col}
</foreach>
from teacher
</delete>
</mapper>
If 元素
if 标签可以对传入的条件进行判断
<where>元素会进行判断,如果它包含的标签中有返回值的话,它就插入一个 ‘where’。
此外,如果标签返回的内容是以 AND 或 OR 开头,它会剔除掉 AND 或 OR。
trim 元素 where 标签,其实用 trim 也可以表示,当 WHERE 后紧随 AND 或则 OR 的时候,就去除 AND 或者 OR。prefix 前缀,prefixOverrides 覆盖首部指定 内容
Set 元素可以把最后一个逗号去掉
• foreach 元素
主要用在构建 in 条件中,它可以在 SQL 语句中进行迭代一个集合。foreach 元素的属性主要有 item,index,collection,open,separator,close。
item 表示集合中每一个元素进行迭代时的别名,index 指定一个名字,用于 表示在迭代过程中,每次迭代到的位置,open 表示该语句以什么开始, separator 表示在每次进行迭代之间以什么符号作为分隔符,close 表示以什 么结束,在使用 foreach 的时候最关键的也是最容易出错的就是 collection 属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的。 – 如果传入的是单参数且参数类型是一个 List 的时候,collection 属 性值为 list – 如果传入的是单参数且参数类型是一个 array 数组的时候, collection 的属性值为 array