Mybatis入门

一、MyBatis概述

MyBatis是一款半自动的ORM持久层框架避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性

ORM:Object Relation Mapping,对象关系映射,即Java对象与数据库表的映射关系

半自动:用Mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句,只需要定义好ORM映射关系,就可以直接进行CRUD操作

SQL灵活性:由于MyBatis需要手写SQL语句,所以它有较高的灵活性

二、搭建MyBatis

1.创建Maven工程

<dependencies>
    <!-- Mybatis核心 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>
    <!-- junit测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.3</version>
    </dependency>
</dependencies>

2.创建核心配置文件

习惯上命名为mybatis-config.xml(将来整合Spring之后此配置文件可省略)

核心配置文件主要用于配置连接数据库的环境及MyBatis全局配置信息,放在src/main/resources下

<?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>
    <!--设置连接数据库的环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/MyBatis"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

3.创建Mapper接口

Mapper接口相当于Javaweb中的DAO,区别是不需要提供实现类,放在src/main/java/mapper下

public interface UserMapper {
    // 添加用户信息
    int insertUser();
}

4.创建MyBatis映射文件

命名方法:表中对应的实体类的类名 + Mapper.xml,放在src/main/resources/mappers下

MyBatis映射文件用于编写SQL,访问和操作表中数据

<?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">
<!--namespace命名空间对应Mapper接口-->
<mapper namespace="mapper.UserMapper">
    <!--对应Mapper接口中的方法int insertUser();-->
    <!--id与方法名一致-->
    <insert id="insertUser">
    insert into t_user values(null,'张三','123',23,'女')
    </insert>
</mapper>

5.测试

@Test
public void testMyBatis() throws IOException {
    //加载核心配置文件
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    //获取SqlSessionFactoryBuilder
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    //获取sqlSessionFactory
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    //获取SqlSession  ture为自动提交事务
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //获取mapper接口实现类
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //测试功能
    int result = mapper.insertUser();
    //提交事务
    //sqlSession.commit();
    System.out.println("result:"+result);
}

sqlSession代表Java与数据库的会话,sqlSessionFactory是生产sqlSession的工厂,可以将上述代码封装为sqlSessionUtils类

public class SqlSessionUtils {
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = null;
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sqlSession;
    }
}

三、增删改查

<!--void updateUser();-->
<update id="updateUser">
    update t_user set username = '张三' where id = 4
</update>

<!--void deleteUser();-->
<delete id="deleteUser">
    delete from t_user where id = 5
</delete>

<!--int insertUser();-->
<insert id="insertUser">
    insert into t_user values(null,'admin','123456',23,'男','12345@qq.com')
</insert>

<!--
查询功能的标签必须设置resultType或resultMap
resultType:自动映射,用于属性名和表中字段名一致的情况
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况(后文详解)
-->
<!--User getUserById();-->
<select id="getUserById" resultType="pojo.User">
    select * from t_user where id = 3
</select>

<!--List<User> getAllUser(); 多条数据用集合接收-->
<select id="getAllUser" resultType="pojo.User">
    select * from t_user
</select>

四、获取SQL语句中的参数值

推荐通过#{ }方式获取参数值(本质为占位符),也可以使用${ }(字符串拼接,需要加单引号)

1.直接获取参数

 Mapper接口:

User checkLogin(String username, String password);

映射文件:

<select id="checkLogin" resultType="User">
    <!--select * from t_user where username = #{arg0} and password = #{arg1}-->
    select * from t_user where username = '${param1}' and password = '${param2}'
</select>

2.使用@Param注解命名参数

Mapper接口:

User checkLoginByParam(@Param("username") String username, @Param("password") String password);

映射文件:

<select id="checkLoginByParam" resultType="User">
    <!--select * from t_user where username = #{param1} and password = #{param2}-->
    select * from t_user where username = #{username} and password = #{password}
</select>

3.接口参数为实体类

 Mapper接口:

int insertUser(User user);

映射文件:

<!--通过实体类属性名获取参数值(本质为get方法)-->
<insert id="insertUser">
    insert into t_user values(null,#{username},#{password},#{age},#{sex},#{email})
</insert>

4.接口参数为map

  Mapper接口:

User checkLoginByMap(Map<String, Object> map);

映射文件:

<!--通过map中的键获取值-->
<select id="checkLoginByMap" resultType="User">
    select * from t_user where username = #{username} and password = #{password}
</select>

五、字段名与属性名不一致

数据库的命名方式为_连接,而Java中使用驼峰命名法,下面介绍在MyBatis中如何解决

(最原始的方式是在SQL语句中为字段名设置别名,再此不做详解)

1.设置核心配置文件

显然MyBatis的设计者也想到了这个问题,并给出了解决方案

<configuration>
    <settings>
        <!--将表中字段的下划线自动转换为驼峰-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>

2.自定义映射resultMap

我们还可以自定义字段与属性之间的映射关系,更为灵活

(1)单表映射

<!--
    resultMap:设置自定义映射关系  type:设置映射关系中的实体类类型
    子标签:
        id:设置主键的映射关系  result:设置普通字段的映射关系
    属性:
        property:设置映射关系中的属性名,必须是type属性所设置的实体类类型中的属性名
        column:设置映射关系中的字段名,必须是sql语句查询出的字段名
-->
<resultMap id="empResultMap" type="Emp">
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
</resultMap>

<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultMap="empResultMap">
    select * from t_emp
</select>

(2)多对一映射

数据库表的多对一关系体现在Java中为一个实体类对象作为另一个实体类对象的属性

<!--方式一:级联属性赋值-->
<resultMap id="empAndDeptResultMapOne" type="Emp">
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
    <result property="dept.did" column="did"></result>
    <result property="dept.deptName" column="dept_name"></result>
</resultMap>

<!--方式二:association-->
<resultMap id="empAndDeptResultMapTwo" type="Emp">
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
    <!--
        association:处理多对一的映射关系
        property:需要处理多对的映射关系的属性名
        javaType:该属性的类型
    -->
    <association property="dept" javaType="Dept">
        <id property="did" column="did"></id>
        <result property="deptName" column="dept_name"></result>
    </association>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid") Integer eid);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapTwo">
    select * from t_emp left join t_dept on t_emp.did = t_dept .did where t_emp.eid = #{eid}
</select>

<!--方式三:分步查询-->
<resultMap id="empAndDeptByStepResultMap" type="Emp">
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
    <!--
        select:设置分步查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
        column:设置分布查询的条件
        fetchType:当开启了全局的延迟加载之后,可通过此属性手动控制延迟加载的效果
        fetchType="lazy|eager":lazy表示延迟加载,eager表示立即加载
    -->
    <association property="dept"
                 select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                 column="did"
                 fetchType="eager"></association>
</resultMap>
<!--Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
<select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
    select * from t_emp where eid = #{eid}
</select>

(3)一对多映射

一对多映射在Java中体现在一个实体类对象的集合作为另一个实体类的属性

<resultMap id="deptAndEmpResultMap" type="Dept">
    <id property="did" column="did"></id>
    <result property="deptName" column="dept_name"></result>
    <!--
        collection:处理一对多的映射关系
        ofType:表示该属性所对应的集合中存储数据的类型
    -->
    <collection property="emps" ofType="Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
    </collection>
</resultMap>
<!--Dept getDeptAndEmp(@Param("did") Integer did);-->
<select id="getDeptAndEmp" resultMap="deptAndEmpResultMap">
    select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
</select>

<!--分布查询-->
<resultMap id="deptAndEmpByStepResultMap" type="Dept">
    <id property="did" column="did"></id>
    <result property="deptName" column="dept_name"></result>
    <collection property="emps"
                select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
                column="did" fetchType="eager"></collection>
</resultMap>
<!--Dept getDeptAndEmpByStepOne(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpByStepResultMap">
    select * from t_dept where did = #{did}
</select>

六、动态SQL

1.if

判断test中的语句是否为真

<select id="getEmpByConditionOne" resultType="Emp">
    select * from t_emp where 1=1
    <if test="empName != null and empName != ''">
        emp_name = #{empName}
    </if>
</select>

2.where

where一般与if一同使用,在if成立时会在语句后加上where关键字再添加if中的内容,如果所有的if都为false,则不会添加where关键字

<select id="getEmpByConditionTwo" resultType="Emp">
    select * from t_emp
    <where>
        <if test="empName != null and empName != ''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
    </where>
</select>

3.trim

trim用于去掉或添加标签中的内容

常用属性: prefix:在trim标签中的内容的前面添加某些内容

                   prefixOverrides:在trim标签中的内容的前面去掉某些内容

                   suffix:在trim标签中的内容的后面添加某些内容

                   suffixOverrides:在trim标签中的内容的后面去掉某些内容

<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp
    <trim prefix="where" suffixOverrides="and|or">
        <if test="empName != null and empName != ''">
            emp_name = #{empName} and
        </if>
        <if test="age != null and age != ''">
            age = #{age} or
        </if>
    </trim>
</select>

4.choose { when otherwise }

相当于switch{case default},即有一个条件满足则不再执行其他条件,无条件满足时执行otherwise

<select id="getEmpByChoose" resultType="Emp">
    select * from t_emp
    <where>
        <choose>
            <when test="empName != null and empName != ''">
                emp_name = #{empName}
            </when>
            <when test="age != null and age != ''">
                age = #{age}
            </when>
            <otherwise>
                did = 1
            </otherwise>
        </choose>
    </where>
</select>

5.foreach

循环实现批量操作

<!--int deleteMoreByArray(@Param("eids") Integer[] eids);-->
<delete id="deleteMoreByArray">
    delete from t_emp where
    <!--separator为分隔符-->
    <foreach collection="eids" item="eid" separator="or">
        eid = #{eid}
    </foreach>
    <!--
        delete from t_emp where eid in
        open、close分别为开始和结束处添加的内容
        <foreach collection="eids" item="eid" separator="," open="(" close=")">
            #{eid}
        </foreach>
    -->
</delete>

<!--int insertMoreByList(@Param("emps") List<Emp> emps);-->
<insert id="insertMoreByList">
    insert into t_emp values
    <foreach collection="emps" item="emp" separator=",">
        (null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null)
    </foreach>
</insert>

6.sql片段

记录一段常用的sql片段,使用时通过标签引入

<sql id="empColumns">eid,emp_name,age,sex,email</sql>

<select id="getEmpByCondition" resultType="Emp">
    select <include refid="empColumns"></include> from t_emp
</select>

七、缓存

1.一级缓存

一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据时就会从缓存中直接获取,不会从数据库重新访问

使一级缓存失效的四种情况:不同的SqlSession对应不同的一级缓存、同一个SqlSession但是查询条件不同、同一个SqlSession两次查询期间执行了任何一次增删改操作、同一个SqlSession两次查询期间手动清空了缓存

2.二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取(一个数据源对应一个SqlSessionFactory,二级缓存确保了不会存在脏读)

二级缓存开启条件:在核心配置文件中,设置全局配置属性cacheEnabled="true"(默认为true,不需要设置)、在映射文件中设置标签<cache />、二级缓存必须在SqlSession关闭或提交之后有效 d>、查询的数据所转换的实体类类型必须实现序列化的接口

使二级缓存失效的情况: 两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

3.缓存查询顺序

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用

如果二级缓存没有命中,再查询一级缓存

如果一级缓存也没有命中,则查询数据库

SqlSession关闭之后,一级缓存中的数据会写入二级缓存

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值