MyBatis笔记

【1.在项目中导入Mybatis(Maven项目)】


 

 - 添加Mybatis依赖

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>

 - 添加mysql连接器依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>myql-connector-java</artifactId>
    <version>?</version>
</dependency>

 

【2.配置Mybatis】


 

 - MyBatis主配置文件mybatis-config.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">    <!-- 文档类型定义(某些框架如果缺少这玩意可能会不工作,比如hibernate) -->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>  <!-- 事务管理器 -->
            <dataSource type="POOLED"> <!-- 数据源配置 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>  <!-- 驱动器类名(该类位于myql-connector-java包中,请导入) -->
                <property name="url" value="jdbc:mysql://localhost:3306/rest"/> <!-- 连接串 -->
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射文件 -->
    <mappers>
        <mapper resource="mapper/user.xml"/>    <!-- resource表示映射文件路径 -->
    </mappers>
</configuration>

 

 - MyBatis映射文件user.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="UserScope">                      <!-- 配置Mapper,一般一个Mapper对应一个实体类 -->
    <select id="getAll" resultType="com.crframe.rest.entity.User">     <!-- 配置一个statement-->
        select * from puser                        <!-- sql语句-->
    </select>
    <select id="getById" resultType="com.crframe.rest.entity.User">
        select * from puser WHERE id = #{id}                <!-- #{...}表示sql参数-->
    </select>
    <insert id="add">
        INSERT INTO puser (name, password) VALUES (#{name}, #{password})
    </insert>
</mapper>

 

 - 参数详解

  •  mapper[namespace]    // mapper的名称空间,可为字符串,或全类名
  •  select[id]        // select语句的标识(JAVA可通过namespace+id找到<select>)
  •  select[result]    // SQL查询返回的类型(容器是自动的,亦可手动指定容器为List,Map等)

 

【3.在JAVA中使用Mybatis】


 

 - 一个简单的查询示例

 public class Restpplication {

    // Mybatis需要用到的一些对象
    private static SqlSessionFactoryBuilder builder = null;
    private static SqlSessionFactory factory = null;
    private static SqlSession session = null;

    static {
        try {
            builder = new SqlSessionFactoryBuilder();
        // 读取配置文件(通过配置文件来生成session工厂)
            factory = builder.build(Resources.getResourceAsStream("mybatis-config.xml"));    
            session = factory.openSession();    // 获取session,session可进行增删改查操作
        } catch (Exception e){
            System.out.println("初始化数据库连接时出现了错误:");
            e.printStackTrace();
        }

    }

    public static void main(String[] args) throws IOException {

        System.out.println("hello");
        // selectList是session内置的查询方法,返回List,User是实体类,参数UserScope.getAll表示statement的id(见上面的Mapper)
        List<User> users = session.selectList("UserScope.getAll"); 
        // 遍历和打印结果
        for(User user : users){
            System.out.println(user);
        }
    }

 - 使用小结

与JDBC相比,Mybatis具有以下特点:
· 数据库连接信息、数据表与实体类的关联是可配置的
· sql语句与业务代码分离
· 很少涉及事务操作
· 自动转换查询结果的类型

 - 补充:

 · 根据测试,数据库的连接出现在SqlSession执行SQL语句前。
 · 如果不想做额外的配置,实体类的属性名应该和表的字段名保持一致,类型也得一致
 · 设置主配置文件的setting.mapUnderscoreToCamelCase = true来开启驼峰映射,last_login_time => lastLoginTime

 

【4.使用DAO】


 

 - DAO示例

public interface UserDao {

    List<User> getAll();
}

 

可以看出DAO是一个接口,我们不需要实现它,该接口可以由Mybatis自动实现。

使用Dao时,mapper文件需要这样:

<mapper namespace="com.crframe.rest.dao.UserDao">...</mapper>

 

如上,namespace需要设置为接口名,这样才能确定mapper文件和DAO接口的关联关系

 

 - 使用DAO

    public static void main(String[] args) throws IOException {

        System.out.println("hello");

        UserDao dao = session.getMapper(UserDao.class);    // getMapper会返回一个UserDao接口的实现类(使用Proxy)
        List<User> users = dao.getAll();        // 之前的配置工作使得dao.getAll()能正确地匹配上mapper文件中的SQL语句
        for(User user : users){
            System.out.println(user);
        }
    }

 

 - 使用小结

 · 使用DAO可以获得更好的代码提示,在实际开发中更常用。
 · DAO也可称之为Mapper

 

【5.使用注解】


 

注解是映射文件的替代品。注解加在Dao(Mapper)上

 - 注解配置

使用注解,主配置文件中的<mapper>需要变成这样

<mapper class="com.crframe.rest.dao.UserDao"/>

可以看出,由原来的映射文件路径变成了类路径,不再需要mapper文件

 - 使用注解

public interface UserDao {

    @Select("Select * from puser")
    List<User> getAll();
    
    @Select("Select * from puser where id = #{id} limit 0,1")
    User getById(int id);


}

可以看出,SQL语句现在跑到注解里了;使用getMapper获得DAO的实例:

User u = new User();
UserDao dao = session.getMapper(UserDao.class);
u = dao.getById(1);
System.out.println(u);

备注:
非查询操作时,并发事务可能会导致一些问题,请注意session的提交和关闭。
我们并没有编写DAO的实现,但确实获得DAO的实例,这使用了代理,返回的dao是代理对象,执行该对象的方法时会触发自定义的回调操作。

 - 多参数时的注解

public interface IllustDao {
    @Select("Select * from pillust limit #{start}, #{count}")
    List<Illust> limit(int start, int count);
}


上述查询运行时会出错,原因是JAVA反射机制(默认情况下)无法得知方法参数的名字,也就无法将SQL语句中的参数与方法的参数对应起来
解决:   
方法1:

@Select("Select * from pillust limit #{param1}, #{param2}")

方法2:

List<Illust> limit(@Param("start") int start, @Param("count") int count); //

 

【6.高级查询】


 

当查询变得复杂时,可能出现以下问题:

① 实体类和数据表的字段名难以保持一致

解决方法:自定义映射

<resultMap id="userMap" type="User" autoMapping="true">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>
<select id="getAll" resultMap="userMap"> <!-- userMap为<ResultMap>的id属性 -->
    select * from puser
</select>

注:resultMap的autoMapping可以设置自动映射,会自动映射没有设置的其他字段
    resultType实际就是开启了autoMapping的resultMap


② 多表查询时复杂结果集的映射比较头疼,比如

Select pillust.*,puser.works as user_works, puser.name as user_name from pillust, puser where pillust.user_id = puser.id and puser.id = 8

解决方法:
 - 返回类型设置为Map,这样会失去实体类的优势,值还要手动装箱
 - 增加一个实体类以保证正确地映射,主要有两种方式:


    - 继承

    class IllustDetail extends Illust{ 
        // extra fields
    }

    - 组合

    class IllustDetail2 { 
        public Illust illust;  
        // extra fields
    }

    使用组合需要额外做些设置,详见下节

 

【7.多表查询时的结果映射】


 

提示: 
 · Mybatis中,可以同时为一个DAO指定映射文件和注解
 · 复杂结果集的映射建议使用映射文件而不是注解

 - 一对一查询的映射 

描述:
包含的列是两张表组合起来的列(一般是一张表为主,另一张表为次)。


实体文件:

public class IllustDetail2 {

    private Illust illust;    // 主要的列
    private String userName; // 额外的列
    private Integer userWorks; // 额外的列
}

作品信息包含作者的基本信息


DAO文件: 

public interface IllustDao {
    List<IllustDetail2> allWithUserInfo();
}

 

映射文件:

<mapper namespace="com.crframe.rest.dao.IllustDao">

    <resultMap id="illustDetail" type="com.crframe.rest.entity.IllustDetail2" autoMapping="true">
        <association property="illust" javaType="com.crframe.rest.entity.Illust" autoMapping="true"/>    <!-- 将主要的列映射到illust属性中 -->
    </resultMap>
    <select id="allWithUserInfo" resultMap="illustDetail"> <!-- 多表查询(用户作品中包含用户信息) -->
        Select pillust.*,puser.works as user_works, puser.name as user_name from pillust left join puser on pillust.user_id = puser.id
    </select>
</mapper>

说明:<association>标签用来指定实体类中的复杂对象的映射方式,该对象一般是其他实体对象。

 

 - 一对多查询的映射 

描述:
一个实体对象包含另一个实体对象的集合
实体文件:

public class UserDetail extends User {
    private List<Illust> illusts;
}

用户信息包含用户的所有作品


DAO文件: 

public interface UserDao {
    List<UserDetail> getWithIllusts(int id);
}

 

映射文件:

<mapper namespace="com.crframe.rest.dao.UserDao">

    <resultMap id="userDetail" type="com.crframe.rest.entity.UserDetail" autoMapping="true">
        <id property="id" column="id"/>
        <collection property="illusts" ofType="com.crframe.rest.entity.Illust" columnPrefix="pillust">
            <id property="id" column="pid"/>
            <result property="userId" column="uid"/>
        </collection>
    </resultMap>
    <select id="getWithIllusts" resultMap="userDetail"> <!-- 多表查询 -->
        Select puser.*, pillust.id as pid, pillust.user_id as uid from puser left join pillust on puser.id = pillust.user_id
    </select>
</mapper>

说明:
<collection>标签用来指定实体类中的集合对象的映射方式,该对象一般是其他实体对象。
mysql查询返回列只在重复列名前添加前缀

【8.级联查询】


 

描述:
对实体类中的某个对象关联一个其他查询。

public class IllustDetail extends Illust implement Serializable {

    private User user;
}

 

如上,illustDetail中携带了用户信息,要获得用户信息,可以先查出illust,再用其中的user_id查出user,因此user字段需要关联一个【其他查询】


Illust.xml映射文件:

<mapper namespace="com.crframe.rest.dao.IllustDao">
    <resultMap id="IllustDetailX" type="com.crframe.rest.entity.IllustDetail" autoMapping="true">
        <id property="id" column="id" javaType="int"/>
        <association property="user" select="com.crframe.rest.dao.UserDao.get" column="user_id" autoMapping="true"/>
    </resultMap>
    <select id="allWithUserInfo2" resultMap="IllustDetailX">
        Select * from pillust;
    </select>
</mapper>

 

User.xml映射文件

<mapper namespace="com.crframe.rest.dao.UserDao">
    <select id="get" resultType="com.crframe.rest.entity.User">
        select * from puser WHERE id = #{id}
    </select>
</mapper>

 

association标签就是用来为user属性关联一个其他查询,select表示要关联的查询的id(由namespace + select id组成),column表示为该查询提供的传参。

 

【9.Mybatis的查询缓存】


 

【10.主配置文件】


 

posted @ 2021-07-22 11:12  liedElxa  阅读(37)  评论(0编辑  收藏  举报