优秀的持久层框架-Mybatis(上)


前言

在使用JDBC输出记录集时,获取不同类型的字段值需要使用不同的方法,这是极其不方便的.mybatis是一个轻量级的ORM(Object Relational Mapping)对象关系映射框架,实现了Java对象和表之间的映射,使Java程序员可以使用对象编程思维来操作数据库,解决了记录输出问题。


一、MyBatis概述

1.1传统JDBC编程

试想一下没有接触过mybatis之前,我们是怎么与数据库进行交互的?
1、 加载数据库驱动
2、 创建并获取数据库链接
3、 创建 statement 对象
4、 拼写 sql 语句
5、 设置 sql 语句中的占位符的值
6、 执行 sql 语句并获取结果
7、 对 sql 执行结果进行解析处理
8、 释放资源

    public ArrayList<Room> roomList(String floor,String build) throws SQLException {
        ArrayList<Room> myList = new ArrayList<>();
        Connection con = null;
        Statement st = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");  // 1.注册JDBC驱动程序 :这需要初始化驱动程序,这样就可以打开与数据库的通信信道。
            String user = "jdbc:mysql://localhost:3306/dormitory_db?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
            String userName1 = "root";
            String password1 = "root";
            con = DriverManager.getConnection(user, userName1, password1);
            PreparedStatement pst1 = con.prepareStatement("SELECT id,number FROM t_room WHERE height=? and buildingid=?");
            pst1.setObject(1,floor);
            pst1.setObject(2,build);
            ResultSet res = pst1.executeQuery();
            while (res.next()) {
                Room room=new Room();
                room.setId(res.getInt("id"));
                room.setNumber(res.getInt("number"));
                myList.add(room);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (st != null) {
                st.close();
            }
            if (con != null) {
                con.close();
            }
        }
        return myList;
    }

试想一下这种做法有什么缺点?
1.数据库频繁释放和连接,造成资源浪费(使用数据库连接池解决)。
2.如果要改动sql语句就需要改动JAVA源代码,不易维护。
3.手动获取查询到的结果,重复操作次数高

1.2 mybatis的历史

原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了 Google Code,随着开发团队转投Google Code 旗下,iBatis3.x正式更名为MyBatis。

Mybatis中文官网: https://mybatis.org/mybatis-3/zh/getting-started.html

1.3 mybatis是什么?

Mybatis是一个基于java的持久层框架,封装了对底层JDBC API的调用细节,并且能自动地将简单的Java对象POJO(plain Old java Object 普通的Java对象)映射成数据库中的记录,自动完成对Java数据库编程中的一些重复性工作。

1.4如何使用?

使用简单的XML或注解来配置和映射原生信息,将接口和 Java 的POJO映射成数据库中的记录。

1.5Mybatis架构

在这里插入图片描述


二、 MyBatis环境搭建

2.1导入MyBatis jar包和数据库驱动包

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>

2.2创建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>
    <!--设置全局配置-->
    <properties resource="config.properties"></properties>

    <settings>
        <setting name="logImpl" value="LOG4J"/>
        <!--java使用标准驼峰,数据库使用下划线连接(数据库不区分大小写)-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--setting name="lazyLoadingEnabled" value="true"/>-->
        <!--指定哪些方法触发延迟查询  -->
        <setting name="lazyLoadTriggerMethods" value=""/>
         <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    <!--设置别名-->
    <typeAliases>
        <typeAlias type="com.ffyc.mybatispro.model.Admin" alias="Admin"></typeAlias>
        <typeAlias type="com.ffyc.mybatispro.model.Employee" alias="Employee"></typeAlias>
        <typeAlias type="com.ffyc.mybatispro.model.Dept" alias="Dept"></typeAlias>
        <typeAlias type="com.ffyc.mybatispro.model.Student" alias="Student"></typeAlias>
    </typeAliases>
    <!--可以修改默认环境-->
    <environments default="development">
        <!--开发环境-->
        <environment id="development">
            <!--事务类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源  使用c3p0连接池-->
            <dataSource type="com.ffyc.mybatispro.util.C3p0DataSourceFactory">
                <property name="driverClass" value="${driverClass}"/>
                <property name="jdbcUrl" value="${jdbcUrl}"/>
                <property name="user" value="${user}"/>
                <property name="password" value="${password}"/>
                <property name="initialPoolSize" value="10"/>
                <property name="maxIdleTime" value="30"/>
                <property name="maxPoolSize" value="100"/>
                <property name="minPoolSize" value="10"/>
                <property name="maxStatements" value="200"/>
            </dataSource>
        </environment>

        <!--工作环境-->
        <!--<environment id="work">
            &lt;!&ndash;事务类型&ndash;&gt;
            <transactionManager type="JDBC"></transactionManager>
            &lt;!&ndash;数据源&ndash;&gt;
            <dataSource type="POOLED">
                <property name="driver" value=""/>
                <property name="url" value=""/>
                <property name="username" value=""/>
                <property name="password" value=""/>
            </dataSource>
        </environment>-->
    </environments>
    <!--添加映射文件-->
    <mappers>
        <mapper resource="mapper/AdminMapper.xml"></mapper>
        <mapper resource="mapper/EmployeeMapper.xml"></mapper>
        <mapper resource="mapper/DeptMapper.xml"></mapper>
        <mapper resource="mapper/Student.xml"></mapper>
    </mappers>

</configuration>

2.3创建映射接口(Mapper接口 主要用于定义有哪些操作)

Mapper 接口开发方法只需要程序员编写 Mapper 接口(相当于 Dao 接口), 由 Mybatis框架根据接口定义创建接口的动态代理对象.

public interface AdminMapper {
    void saveAdmin(Admin admin);
    Admin selectAdmin(int id);
    Admin selectAdminByTwo(@Param("name") String name,@Param("sex") String sex);
    Admin selectAdminByMap(HashMap<String,Object>map);
}

2.4创建和编写sql映射文件(Mapper.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">
<mapper namespace="com.ffyc.mybatispro.mapper.AdminMapper">
    <!--    #{}一般用来传数据,采用预编译的方法,编译好的sql语句再取值,可以防止sql注入
        ${}一般用来传列名,会传入参数字符串,如果想用$传数据可以用'${}'
        useGeneratedKeys="true"   开关
        keyColumn="id"     主键列
        keyProperty="id"   接收主键的属性
        -->
    <!--当数据库的列名和对象的属性名不相同时,可以使用resultMap-->
    <resultMap id="AdminResultMap" type="Admin">
        <!--主键列-->
        <id column="id" property="id"/>
        <!--非主键列-->
        <result property="name" column="ename"/>

    </resultMap>
    <insert id="saveAdmin" parameterType="Admin" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
    insert into admin(name,sex,phone)values(#{name},#{sex},#{phone})
    </insert>
    <!--简单的参数类型不需要设置parameterType-->
    <select id="selectAdmin" resultMap="AdminResultMap">
        SELECT
        e.id,
        e.name ename,
        d.name dname,
        a.name aname
        FROM employee e LEFT JOIN  dept d ON d.id=e.id
        LEFT JOIN admin a ON a.id=e.id
        WHERE e.id=#{id}
    </select>

    <select id="selectAdminByTwo" resultType="Admin">
        select * from admin where name=#{name} and sex=#{sex}
    </select>
    <!--使用resultMap的输出映射,而非resultType-->
    <select id="selectAdminByMap" resultMap="AdminResultMap">
        select * from admin where id=#{id}
    </select>
</mapper>
#{} 占位符,是经过预编译的,编译好 SQL 语句再取值,#方式能够防止 sql 注入
#{}:select * from t_user where uid=#{uid}

${} 拼接符,会传入参数字符串,取值以后再去编译 SQL 语句,$方式无法防止Sql注入  
${}:select * from t_user where uid= '1'

MyBatis 排序时使用 order by 动态参数时需要注意,用$而不是#修改


注意:
1.Mapper.xml 文件中的 namespacemapper 接口的类路径相同。
2.Mapper 接口方法名和 Mapper.xml 中定义的每个 statement 的 id 相同
3.Mapper 接口方法的输入参数类型和 mapper.xml 中定义的每个 sql 的 parameterType 的类型相同
4.Mapper 接口方法的输出参数类型和 mapper.xml 中定义的每个 sql 的 resultType 的类型相同

2.5测试 MyBatis

读取核心配置文件
创建SqlSessionFactory
      openSession()
创建SqlSession	
      getMapper(Class class);获得接口代理对象 
      commit();提交事务
      close();关闭
获得接口代理对象
代理对象.接口中的方法

SqlSessionFactory 接口一旦创建,SqlSessionFactory 就会在整个应用过程中始终存在,所以没有理由去销毁和再创建它,一个应用运行中也不建议多次创建 SqlSessionFactory。如 果真的那样做,会显得很耗时,所以我们创建一个工具类,用来专门创建SqlSessionFactory,保证一个应用运行中只创建一次.且提供获得SqlSession接口类型对象的方法,方便我们操作

public class SqlSessionFactoryUtil {
    public static SqlSessionFactory sqlSessionFactory;
    static{
        Reader reader=null;
        try {
            /*读取配置文件*/
            reader = Resources.getResourceAsReader("mybatis-config.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*SqlSessionFactory  一旦创建,在整个应用程序中都存在,不用销毁再创建,反复传教很耗时 */
       sqlSessionFactory= new SqlSessionFactoryBuilder().build(reader);
    }
    public static SqlSessionFactory getSqlSessionFactory(){
        return sqlSessionFactory;
    }
    /*用来获得SqlSession接口类型对象的方法*/
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

测试代码

    @org.junit.Test
    public void save(){
        Admin admin=new Admin();
        admin.setName("王小丽");
        admin.setPhone("13157900521");
        admin.setSex("女");
        /*SqlSessionFactory  一旦创建,在整个应用程序中都存在,不用销毁再创建,反复传教很耗时 */
        /* SqlSession 创建数据库会话,封装了对数据库操作的方法*/
        SqlSession sqlSession= SqlSessionFactoryUtil.getSqlSessionFactory().openSession();
        AdminMapper adminMapper= sqlSession.getMapper(AdminMapper.class);
        adminMapper.saveAdmin(admin);
        System.out.println(admin.getId());  //可以获得新增数据的主键
        sqlSession.commit();
        sqlSession.close();
    }

在数据库中查看插入成功
在这里插入图片描述
注意:使用单元测试需要在maven中加入依赖

      <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>provided</scope>  <!--不会打包到war包-->
        </dependency>

注意:Mybatis默认不自动提交事务,在进行增删改操作时,需要自己提交事务,否则数据不会变化到数据库中


三、参数传递和结果处理

3.1参数传递

1.简单参数传递
简单的参数形式不需要使用parameterType参数定义

接口中的方法
     Admin selectAdmin(int id);
     
sql映射文件
    <!--简单的参数类型不需要设置parameterType-->
    <select id="selectAdmin" resultType="Admin">
        SELECT
        e.id,
        e.name ename,
        d.name dname,
        a.name aname
        FROM employee e LEFT JOIN  dept d ON d.id=e.id
        LEFT JOIN admin a ON a.id=e.id
        WHERE e.id=#{id}
    </select>

2.多个参数传递
多个参数使用@Param(“id”)绑定

接口中的方法
     Admin selectAdminByTwo(@Param("name") String name,@Param("sex") String sex);
     
sql映射文件
      <select id="selectAdminByTwo" resultType="Admin">
         select * from admin where name=#{name} and sex=#{sex}
      </select>

3.复杂参数传递
如果传入一个复杂的对象,就需要使用 parameterType 参数进行类型定义

接口中的方法
     void saveAdmin(Admin admin);

sql映射文件
    <insert id="saveAdmin" parameterType="Admin">
         insert into admin(name,sex,phone)values(#{name},#{sex},#{phone})
    </insert>

4.Map对象传递
在sql中使用表达式获取map的键即可

接口中的方法
     Admin selectAdminByMap(HashMap<String,Object>map);

sql映射文件
    <select id="selectAdminByMap" resultType="Admin">
        select * from admin where id=#{id}
    </select>

3.2结果处理

1.返回简单基本类型

接口中的方法
     public int findAdminCount(); 

sql映射文件
    <select id="findAdminCount" resultType="int"> 
       select count(*) from userInfo 
    </select>

2.POJO对象输出映射
如果表中的类名与类中的属性名完全相同,mybatis会自动将查询结果封装 到POJO对象中.

接口中的方法
     Admin selectAdminByTwo(@Param("name") String name,@Param("sex") String sex);
     
sql映射文件
    <select id="selectAdminByTwo" resultType="Admin">
        select * from admin where name=#{name} and sex=#{sex}
    </select>

3.定义resultMap

接口中的方法
    Admin selectAdmin(int id);

sql映射文件
    <!--当数据库的列名和对象的属性名不相同时,可以使用resultMap-->
    <resultMap id="AdminResultMap" type="Admin">
        <!--主键列-->
        <id column="id" property="id"/>
        <!--非主键列-->
        <result  column="ename" property="name"/>
    </resultMap>

    <select id="selectAdmin" resultMap="AdminResultMap">
        SELECT
        e.id,
        e.name ename,
        d.name dname,
        a.name aname
        FROM employee e LEFT JOIN  dept d ON d.id=e.id
        LEFT JOIN admin a ON a.id=e.id
        WHERE e.id=#{id}
    </select>

注意:
(1). resutlMap 的 id 属性是 resutlMap 的唯一标识
(2). id 标签映射主键,result 标签映射非主键
(3). property 设置 POJO 的属性名称,column 映射查询结果的列名称

4.多表关联处理结果集
部门实体类包含以下几个成员变量

    private  int id;
    private String name;
    private List<Employee> employees=new ArrayList<Employee>();
    private Admin admin;

由于部门中有一个Admin对象和多个employees对象组成的List集合,所以利用普通的结果集对象无法实现封装
解决方法:多表关联处理结果集,利用resultMap 元素中association , collection 元素

association 一对一结果映射
Collection 关联元素处理一对多关联。

接口中的方法
    Dept selectDept(int id);

sql映射文件
    <resultMap id="DeptResultMap" type="Dept">
    
        <!--主键列-->
        <id column="id" property="id"/>
        <!--非主键列-->
        <result property="name" column="dname"/>
        
        <association property="admin" javaType="Admin">
            <result property="name" column="aname"/>
        </association>
        
        <collection property="employees" javaType="list" ofType="Employee">
            <result property="name" column="ename"></result>
        </collection>
        
    </resultMap>
    
    <select id="selectDept" resultMap="DeptResultMap">
     SELECT
     d.id,
     d.name dname,
     a.name aname,
     e.name ename
     FROM dept d
     LEFT JOIN admin a ON d.adminid=a.id
     LEFT JOIN employee e ON e.deptid=d.id
     WHERE d.id=#{id}
    </select>

总结

本章主要介绍了Mybatis的基本概述,mybatis的环境搭建以及参数传递和结果处理。Mybatis对数据访问层进行了封装,使程序员不用进行以往重复性的操作。Mybatis在java框架部分难度不算太大,但是作为第一个学习的框架,Mybatis可以为后续框架的学习打下基础。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JinziH Never Give Up

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值