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('张三','zhangsan@126.com',22);
insert into student(name,email,age) values('李四','lisi@126.com',21);
insert into student(name,email,age) values('王五','wangwu@163.com',22);
insert into student(name,email,age) values('赵六','zhaoliun@qq.com',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","dcs@qq.com",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","zhangsan@123.com",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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值