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
java 复制代码
 <dependency>
           <groupId>org.mybatis</groupId>
           <artifactId>mybatis</artifactId>
           <version>3.4.2</version>
       </dependency>
3.创建一个全局的mybatis配置文件,配置数据库进行链接
java 复制代码
<?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.创建数据库,创建表
sql 复制代码
create database ssmdb

create table admin(
id int primary key auto_increment,
account varchar(10),
password varchar(10),
gender varchar(10)
)
5.创建一个访问接口,定义方法
java 复制代码
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.创建接口对应映射文件
java 复制代码
<?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();

java 复制代码
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 意味着创建与数据库链接会话,该接口中封装了对数据库操作的方 法,与数据库会话完成后关闭会话。

java 复制代码
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,用完关闭,但是访问量大了后,每次都要创建新的连接对象,用完关闭,比较耗时

使用数据库连接池,在池(集合)中事先创建一些链接对象,用完不销毁,还回到池中这样就减小频繁创建销毁链接对象。

java 复制代码
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})

java 复制代码
<!--useGeneratedKeys="true" keyProperty="id" keyColumn="id"-->
    <insert id="insert" parameterType="Admin" >
        insert into admin(account,password,gender) values (#{account},#{password},#{gender})
    </insert>

修改 "唯一标识" parameterType="参数类型">

java 复制代码
 <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}

java 复制代码
 <delete id="deleteadmin" parameterType="int">
        delete from admin where id=#{id}
    </delete>

查询 唯一标识" resultType="返回结果集类型"> select * from admin where id= #{id}

java 复制代码
 <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 传列名

java 复制代码
 <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 关联元素处理一对多关联

java 复制代码
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>
java 复制代码
<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 属性,两者配置方法 相同

java 复制代码
 <!--
    =============================================================
    关联查询方式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>
java 复制代码
  <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

java 复制代码
<?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

相关推荐
zquwei17 分钟前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
TT哇24 分钟前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
火烧屁屁啦1 小时前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
飞飞-躺着更舒服1 小时前
【QT】实现电子飞行显示器(改进版)
开发语言·qt
w_31234541 小时前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安1 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA1 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
Q_19284999061 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟2 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S2 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring