mabatis预习博客

一、概述

1.1、框架是什么

1.1.1 框架定义

  框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种认为,框架是可被应用开发者定制的应用骨架、模板。
  简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能。
  框架安全的,可复用的,不断升级的软件。

1.1.2框架解决的问题

	框架要解决的最重要的一个问题是技术整合,在 J2EE 的 框架中,有着各种各样的技术,不同的应用,系统使用不同的技术解决问题。需要从 J2EE 中选择不同的技术,而技术自身的复杂性,有导致更大的风险。企业在开发软件项目时,主要目的是解决业务问题。 即要求企业负责技术本身,又要求解决业务问题。这是大多数企业不能完成的。框架把相关的技术融合在一起,企业开发可以集中在业务领域方面。
    另一个方面可以提供开发的效率。

1.2 MyBatis框架

1.2.1、什么是mybatis框架

  1. mybatis框架就是一个封装jdbc的持久层框架,它和hibernate都属于ORM框架,但是,hibernate是一个完整的orm框架,mybatis是不完全的mybatis框架
  2. mybatis框架让程序员只关注sql本身,而不需要去关注如连接的创建,statement的创建等操作
  3. mybatis会将输入的参数输出的结果进行映射

1.2.2、MyBatis框架的结构

在这里插入图片描述

二、mybatis快速入门

2.1、入门案例

  1. 创建MysqL数据库和表
#创建数据库ssm
CREATE DATABASE ssm DEFAULT CHARSET utf8;

#使用(打开)ssm数据库
use ssm;

#创建表student
CREATE TABLE `student` (
`id` int(11)  AUTO_INCREMENT primary key ,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into student(name,email,age) values('张三','[email protected]',22);
insert into student(name,email,age) values('李四','[email protected]',21);
insert into student(name,email,age) values('王五','[email protected]',22);
insert into student(name,email,age) values('赵六','[email protected]',24);
select * from student;
  1. 创建maven工程,添加依赖
		<dependency>
            <groupId>MysqL</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.23</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.1</version>
        </dependency>
  1. 编写student实体类
public class Student {
    private int id;
    private String name;
    private String email;
    private int age;
}
  1. 在resources下添加jdbc,properties文件

    在这里插入图片描述

  2. 创建,编写mybatis核心配置文件(sqlMapConfig.xml,注意标签的顺序)
<?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>
    <!-- 读取属性文件(jdbc.properties
            属性:
                resource:从resources目录下找到指定名称文件加载
                url:使用绝对路径加载属性文件
    -->
    <properties resource="jdbc.properties"></properties>

    <!--设置日志,输出底层执行的代码-->
    <settings>
        <!--值是固定的-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--给实体类注册别名-->
    <typeAliases>
        <!--单个注册-->
        <!--<typeAlias type="com.bluemsun.entity.Student" alias="student"></typeAlias>-->

        <!--批量注册(别名就是实体类类名的驼峰命名)-->
        <package name="com.bluemsun.entity"/>
    </typeAliases>

    <!-- 配置数据库的环境变量(数据库连接配置)-->
    <environments default="development">
        <environment id="development">
            <!-- 配置事务管理器
                    type:指定事务的管理方式
                        JDBC:事务控制交给程序员处理
                        MANAGED:由容器(spring)来管理事务
            -->
            <transactionManager type="JDBC"></transactionManager>

            <!-- 配置数据源
                    type:指定不同的配置方式
                        JNDI:java命名目录接口,在服务器端进行数据库连接池的管理
                        POOLED:使用数据库连接池
                        UNPOOLED:不使用数据库连接池
            -->
            <dataSource type="POOLED">
                <!-- 配置数据库连接的基本配置-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>

            </dataSource>
        </environment>
    </environments>

    <!-- 注册mapper.xml文件-->
</configuration>
  1. 创建,编写StudentMapper.xml文件(该文件完成数据库中student表的所有增删改查的操作.)
<?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:是整个文件的大标签,用来开始和结束xml文件
        属性:
            namespace:指定命名空间(相当于包名),用来区分不同的mapper.xml
            文件中相同的id属性
-->
<mapper namespace="dcs">

    <!--实现查询功能的select子标签-->
    <!--
        resultType:指定查询返回的结果集的类型,如果是集合则必须是泛型
        parameterType:如果有参数,则通过它来指定参数类型
    -->
    <!--查询所有-->
    <select id="getAll" resultType="student">
        select id,name,email,age from student
    </select>

    <!--通过id查询部分-->
    <select id="getById" parameterType="int" resultType="student">
        select id,name,email,age from student where id=#{id}
    </select>

    <!--模糊查询-->
    <select id="getByName" parameterType="string" resultType="student">
        select id,name,email,age
        from student
        <!--
            where name like '%${name}%'
            上面这种写法报错,因为JAVA反射只能获取方法参数的类型,但无从得知方法参数的名字的
            _parameter则是java对通过反射获取参数后,给参数取的别名。
            3.5.1及以下的版本,模糊查询时,如果入参是简单类型和String要用{_parameter}或者{value}
            3.5.1以上的版本,如果入参是简单类型或String,花括号中随便写
        -->
        where name like '%${value}%'
    </select>
    
    <!--增加学生-->
    <insert id="insert" parameterType="student">
        insert into student (name,email,age) values (#{name},#{email},#{age})
    </insert>

    <!--按主键删除学生-->
    <delete id="delete" parameterType="int">
        delete from student where id = #{id};
    </delete>

    <!--更新-->
    <update id="update" parameterType="student">
        update student set name = #{name},email = #{email},age = #{age}
        where id = #{id}
    </update>
</mapper>
  1. 在主配置文件sqlMapConfig.xml文件注册mapper.xml文件
<!-- 注册mapper.xml文件-->
    <mappers>
        <mapper resource="StudentMapper.xml"></mapper>
    </mappers>
  1. 测试
public class MyTest {

    sqlSession sqlSession;

    //会在所有test执行前执行
    @Before
    public void opensqlSession() throws IOException {
        //使用文件流读取核心配置文件sqlMapConfig.xml
        InputStream in = Resources.getResourceAsstream("sqlMapConfig.xml");
        //创建sqlSessionFactory工厂
        sqlSessionFactory factory = new sqlSessionFactoryBuilder().build(in);
        //取出sqlSession的对象
        sqlSession = factory.openSession();
    }
    
    //test执行后执行
    @After
    public void close(){
        //关闭sqlSession
        sqlSession.close();
    }


    @Test
    public void selectTest01() throws IOException {
        //完成查询操作
        List<Student> list = sqlSession.selectList("dcs.getAll");
        list.forEach(student -> System.out.println(student));
    }

    @Test
    public void selectTest02() throws IOException {
        //完成查询操作
        Student student = sqlSession.selectOne("dcs.getById",2);
        System.out.println(student);
    }

    @Test
    public void selectTest03() throws IOException {
        //完成查询
        List<Student> list = sqlSession.selectList("dcs.getByName","李");
        list.forEach(student -> System.out.println(student));
    }

    @Test
    public void insertTest01() throws IOException{
        Student stu = new Student("dcs","[email protected]",19);
        int result = sqlSession.insert("dcs.insert", stu);
        System.out.println(result);
        sqlSession.commit();    //手动提交事务
    }

    @Test
    public void deleteTest01() throws IOException{
        int result = sqlSession.delete("dcs.delete", 7);
        System.out.println(result);
        sqlSession.commit();    //手动提交事务
    }

    @Test
    public void updateTest01() throws IOException{
        int result = sqlSession.update("dcs.update", new Student(1,"zhangsan","[email protected]",30));
        System.out.println(result);
        sqlSession.commit();    //手动提交事务
    }
}

2.2、MyBatis对象分析

(1)Resources 类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。

(2)sqlSessionFactoryBuilder 类
sqlSessionFactory 的 创 建 , 需 要 使 用 sqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由 于sqlSessionFactoryBuilder对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将该 对象创建一个方法内的局部对象,方法结束,对象销毁。

(3)sqlSessionFactory 接口
sqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建 sqlSession 需要使用 sqlSessionFactory 接口的的 openSession()方法。
A.openSession(true):创建一个自动提交功能sqlSession
B.openSession(false):创建一个自动提交功能sqlSession,需手动提交
C.openSession():同 openSession(false)

(4)sqlSession 接口
sqlSession  接口对象用于执行持久化操作。一个 sqlSession  对应着一次数据库会话,一次会话以sqlSession 对象的创建开始,以 sqlSession 对象的关闭结束。
sqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭。再次需要会话,再次创建。 sqlSession 在方法内部创建,使用完毕后关闭

三、动态代理

3.1、动态代理开发规范

MyBatis框架使用动态代理的方式来进行数据库的访问.
Mapper接口的开发相当于是过去的Dao接口的开发。由MyBatis框架根据接口定义创建动态代理对象,代理对象的方法体同Dao接口实现类的方法。在设计时要遵守以下规范.

  1. Mapper接口与Mapper.xml文件在同一个目录下
  2. Mapper接口的完全限定名与Mapper.xml文件中的namespace的值相同。
  3. Mapper接口方法名称与Mapper.xml中的标签的statement 的ID完全相同。
  4. Mapper接口方法的输入参数类型与Mapper.xml的每个sql的parameterType的类 型相同
  5. Mapper接口方法输出参数与Mapper.xml的每个sql的resultType的类型相同。
  6. Mapper文件中的namespace的值是接口的完全限定名称.
  7. sqlMapConfig.xml文件注册时,使用class属性=接口的完全限定名.

3.2、开发步骤

  1. 新建项目,添加依赖
  2. 加入jdbc.properties属性配置文件
  3. 编写实体类
  4. 创建,编写环境配置文件(sqlMapConfig.xml)
  5. 创建,编写Mapper接口
public interface UsersMapper {
    //查询所有
    List<Users> getAll();

    //更新数据
    int updateById(Users users);

    //优化的模糊查询(不用${},没有sql注入问题)
    List<Users> getByName(String username);

    //模糊查询名字或住址
    List<Users> getByNameAddr(@Param("colName") String colName, @Param("colValue") String colValue);
}
  1. 创建,编写Mapper.xml文件(与Mapper接口重名,后缀不同)
<?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.bluemsun.mapper.UsersMapper">
    <!--查询所有-->
    <select id="getAll" resultType="users">
        select id,username,birthday,sex,address
        from users
    </select>

    <!--根据id更新一条数据-->
    <update id="updateById" parameterType="users">
        update users
        set username = #{userName},birthday = #{birthday},sex = #{sex},address = #{address}
        where id = #{id}
    </update>

    <!--优化后的模糊查询-->
    <select id="getByName" parameterType="string" resultType="users">
        select id,username,birthday,sex,address
        from users
        where username like concat('%',#{username},'%')
    </select>

    <!--模糊查询名字或者地址-->
    <!--
        ${}可以进行字符串替换
        如果入参有多个,那么就不写parameterType属性
    -->
    <select id="getByNameAddr" resultType="users">
        select id,username,birthday,sex,address
        from users
        where ${colName} like concat('%',#{colValue},'%')
    </select>
</mapper>
  1. 注册mapper.xml文件
   <!--注册mapper.xml文件-->
    <mappers>
		<!--<mapper class="com.bluemsun.mapper.UsersMapper"></mapper>-->
        <!--批量注册-->
        <package name="com.bluemsun.mapper"></package>
    </mappers>
  1. 测试
public class Mytest {

    sqlSession sqlSession;
    //动态代理对象
    UsersMapper uMapper;
    //日期格式化刷子
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    @Before
    public void opensqlSession() throws IOException {
        //读取核心配置文件
        InputStream in = Resources.getResourceAsstream("sqlMapConfig.xml");
        //创建sqlSessionFactory工厂
        sqlSessionFactory factory = new sqlSessionFactoryBuilder().build(in);
        //获取sqlSession对象
        sqlSession = factory.openSession();
        //获取动态代理对象
        uMapper = sqlSession.getMapper(UsersMapper.class);
    }

    @After
    public void closesqlSession() throws IOException{
        sqlSession.close();
    }

    @Test
    public void selectTest01(){
        //调用接口中的方法
        List<Users> list = uMapper.getAll();
        list.forEach(users -> System.out.println(users));
    }

    @Test
    public void selectByName(){
        List<Users> list = uMapper.getByName("张");
        list.forEach(users -> System.out.println(users));
    }

    @Test
    public void selectByNameAddr(){
        List<Users> list = uMapper.getByNameAddr("sex","1");
        list.forEach(users -> System.out.println(users));
    }

    @Test
    public void updateTest01() throws ParseException {
        int result = uMapper.updateById(new Users(7,"dcs",sdf.parse("2002-12-2"),'1',"重庆奉节"));
        System.out.println(result);
        //切记:要手动提交事务
        sqlSession.commit();
    }

}

四、动态sql

动态 sql 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 sql 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 sql,可以彻底摆脱这种痛苦。使用动态 sql 并非一件易事,但借助可用于任何 sql 映射语句中的强大的动态 sql 语言,MyBatis 显著地提升了这一特性的易用性。

4.1、< sql>标签

当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为常量,方便调用

<!--所有列名,查找users表的所有列的数据时可以引用-->
<sql id="allCols">
	id,username,birthday,sex,address
</sql>

4.2、< include>标签

用于引用定义的常量。

<!--查询所有-->
    <select id="getAll" resultType="users">
    	<!--
    		等同于:
    			select id,username,birthday,sex,address
    			from users
    	-->
        select <include refid="allCols"></include>
        from users
    </select>

4.3、< if>和< where>标签

< if>进行条件判断
< where> 进行多条件拼接,在查询,删除,更新中使用.

	<!--通过动态SQL查询过-->
    <select id="getByDynamicsql" resultType="users" parameterType="users">
        select <include refid="allCols"></include>
        from users
        <where>
            <if test="userName != null and userName != ''">
                and username like concat('%',#{userName},'%')
            </if>
            <if test="birthday != null">
                and birthday = #{birthday}
            </if>
            <if test="sex != '' and sex != null">
                and sex = #{sex}
            </if>
            <if test="address != null and address != ''">
                and address like concat('%',#{address},'%')
            </if>
        </where>
    </select>

4.3、< set>标签

有选择的进行更新处理,至少更新一列.能够保证如果没有传值进来,则数据库中的数据保持不变.

<!--使用动态sql更新数据-->
    <update id="updateByDynamicsql" parameterType="users">
        update users
        <set>
            <if test="userName != null and userName != ''">
                username = #{userName},
            </if>
            <if test="birthday != null">
                birthday = #{birthday},
            </if>
            <if test="sex != '' and sex != null">
                sex = #{sex},
            </if>
            <if test="address != null and address != ''">
                address = #{address},
            </if>
        </set>
        where id = #{id}
    </update>

4.4、< choose>标签

有时候,我们不想用到所有的查询条件,只想选择其中的一个查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句

<!--测试choose和when-->
    <select id="getByChoose" resultType="users" parameterType="users">
        select <include refid="allCol"></include>
        from users
        <where>
            <choose>
                <when test="userName != null and userName != ''">
                    and username like concat('%',#{userName},'%')
                </when>
                <when test="sex != null and sex != ''">
                    and sex = #{sex}
                </when>
                <otherwise>
                    and address like concat('%',#{address},'%')
                </otherwise>
            </choose>
        </where>
    </select>

4.5、< foreach>标签

< foreach>主要用来进行集合或数组的遍历,主要有以下参数:

collection:collection 属性的值有三个分别是 list、array、map 三种,分别对应的参数类型为:List、数组、map 集合。
item :循环体中的具体对象。支持属性的点路径访问,如item.age,item.info.details,在list和数组中是其中的对象,在map中是value。
index :在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。
open :表示该语句以什么开始
close :表示该语句以什么结束
separator :表示元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。
<!--foreach-->
    <select id="getByForeach" resultType="users">
        select <include refid="allCols"></include>
        from users
        where id in
        <foreach collection="array" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </select>

五、表的关联关系

我们通常说的关联关系有以下四种,一对多关联,多对一关联,一对一关联,多对多关联。关联关系是有方向的。如果是高并发的场景中,不适合做表的关联。

5.1、一对多(customer --> order)

在一对多关联关系中,一方(客户)中有多方(订单)的集合 ,所以要使用<collection>标签来映射多方的属性

核心代码

实体类

Customer --> Order		一对多
order --> Customer      多对一

//客户
public class Customer {
    private int id;
    private String name;
    private int age;

    //该用户下的所有订单
    List<Order> orders;
}

//订单
public class Order {
    private int id;
    private String orderNumber;
    private double orderPrice;

    //下这个订单的用户
    private Customer customer;
}

接口:

public interface CustomerMapper {

    //查询所有(方案一)
    List<Customer> getAll();

    //查询所有(方案二)
    List<Customer>  getAll2();

    //查询所有(方案三)
    List<Customer> getAll3();
}

CustomerMapper.xml文件
方案一:编写表关联查询sql语句,进行结果集映射

 <!--方法一:表的关联查询,起别名-->
    <resultMap id="customerMap" type="customer">
        <!--主键-->
        <id property="id" column="cid"></id>
        <!--非主键-->
        <result property="name" column="cname"></result>
        <result property="age" column="cage"></result>
        <!--其他属性-->
        <collection property="orders" ofType="order">
            <id property="id" column="oid"></id>
            <result property="orderNumber" column="onum"></result>
            <result property="orderPrice" column="oprice"></result>
        </collection>
    </resultMap>
    <select id="getAll" resultMap="customerMap">
        select c.id cid,c.name cname,c.age cage,o.id oid,o.orderNumber onum,o.orderPrice oprice
        from customer c left join orders o on c.id = o.customer_id
    </select>

方案二:嵌套查询(在CustomerMapper.xml文件中编写查询orders表的sql

<!--
        方法二:使用嵌套查询的方式,不用表关联查询
            瑕疵:在CustomerMapper.xml文件中编写了对orders表的sql语句
    -->
    <resultMap id="customerMap2" type="customer">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>

        <!--column是当前客户表的id,传给嵌套查询作为入参进行查询返回该客户下的所有订单集合-->
        <collection property="orders" column="id" ofType="order" 
        select="getorderByCustomerId"></collection>
    </resultMap>
    <select id="getAll2" resultMap="customerMap2">
        select id,name,age from customer
    </select>
    <!--嵌套查询,查询orders表-->
    <select id="getorderByCustomerId" resultType="order" parameterType="int">
        select id,orderNumber,orderPrice from orders where customer_id = #{id}
    </select>

方案三:嵌套查询(每个mapper里只有自己的增删改查)

CustomerMapper.xml文件

 <!--方法三:把对订单的嵌套查询语句写在OrderMapper.xml文件中-->
    <resultMap id="customerMap3" type="customer">
        <id property="id" column="id"></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>

        <!--column是当前客户表的id,传给嵌套查询作为入参进行查询返回该客户下的所有订单集合-->
        <collection property="orders" column="id" ofType="order"
                    select="com.bluemsun.mapper.OrderMapper.selectOrderByCustomerId">
        </collection>
    </resultMap>
    <select id="getAll3" resultMap="customerMap3">
        select id,name,age from customer
    </select>

OrderMapper.xml文件
 <!--嵌套查询,供查询某客户下的所有订单-->
    <select id="selectOrderByCustomerId" resultType="order" parameterType="int">
        select id,orderNumber,orderPrice from orders where customer_id = #{id}
    </select>

5.2、多对一(order --> customer)

在多对一关联关系中,多方(订单)中持有一方(客户)的对象,要使用标签<association>标签来映射一方的属性

核心代码

实体类:(和上面一对多一样)

接口:

public interface OrderMapper {
    //查询所有(嵌套查询)
    List<Order> getAll();
}

OrderMapper.xml文件

OrderMapper.xml

<!--查询所有:嵌套查询-->
    <resultMap id="orderMap" type="order">
        <id property="id" column="id"></id>
        <result property="orderNumber" column="orderNumber"></result>
        <result property="orderPrice" column="orderPrice"></result>

        <association property="customer" column="customer_id"
                 	select="com.bluemsun.mapper.CustomerMapper.selectCumtomerByOrderId">
        </association>
    </resultMap>
    <select id="getAll" resultMap="orderMap">
        select id,orderNumber,orderPrice,customer_id from orders
    </select>


CustomerMapper.xml
<!--嵌套查询,供查找某个订单对应的客户-->
    <select id="selectCumtomerByOrderId" resultType="customer" parameterType="int">
        select id,name,age from customer where id = #{id}
    </select>

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...