Mybatis 学习

基础知识学习

框架:开发中说的框架,通常是一种解决方案,其内部封装了一些细节,使开发者可以通过很少的时间实现功能,提高开发效率。

三层架构

​ 表现层:用于展示数据。

​ 业务层:用于处理业务需求,我们自己编码实现。

​ 持久层:用于与数据库交互。

由于Mybatis是关于持久层的,后面就专注于持久层的知识。

持久层技术解决方案

  • JDBC技术:是jdk官方提供的数据库交互规范。
  • Spring中的JdbcTemplate:是spring提供的数据库交互工具,其在JDBC上进行了简单封装
  • Apache的DButils:与JdbcTemplate相似,也是实现了简单封装。

说明:上述三者都并非框架。JDBC是一套规范,后两者是该规范的简单实现。他们都只是工具,因为其并没有形成一套完整的解决方案,我们在开发中仍需要做很多事。

myBatis概述

​ mybatis是一个优秀的基于java 的持久层框架,其内部封装了jdbc,使开发者只需要关注sql语句本身,而不用花费精力去处理加载驱动、创建连接、创建statement等繁杂过程。

​ mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中的sql的动态参数进行映射(如:Object.query("select * from tableName where id=?",db.getId())),生成最终的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。

​ 采用思想:ORM(Object Relational Mapping,对象关联映射),其解决了实体对象到数据库表中的映射问题。对jdbc进行了封装,屏蔽了jdbc api底层访问的细节,使开发者无需与其打交道,就可以完成数据库持久化操作。


Mybatis环境搭建

小细节${}#{}的区别:效果都是占位,然后等待编译时进行变量替换。区别在于#{}替换后,会加上引号,表明该值是字符串;而${}替换后是不加字符串的,可以用于properties文件的引用、sql语句中如ORDER BY ${}等。

注意:当使用${}作为sql语句时,内部是固定占位符:${value}

大致开发步骤

  • 1.建立maven工程并导入依赖
  • 2.创建实体类和dao的接口
  • 3.创建Mybatis的主配置文件:sqlMapConfig.xml
  • 4.创建每个dao对应的映射配置文件:SubjectsDAOInterface.xml

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>
    <!-- 配置mybatis的主配置文件 -->
    <environments default="mysql">
        <!-- 配置mysql的环境 -->
        <environment id="mysql">
            <!-- 配置事务管理器 -->
            <transactionManager type="JDBC">
                <property name="dataSource" value="dataSource"/>
            </transactionManager>
            <!-- 配置数据源 -->
            <dataSource type="POOLED">
                <!-- 配置连接池的基本信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/TestBase"/>
                <property name="username" value="sun"/>
                <property name="password" value="sunlin"/>
            </dataSource>
        </environment>
    </environments>
    
    <!-- 指定映射配置文件的位置,其代表每个dao独立的配置文件;【注意resource的值是用'/’标识目录父子关系,而非‘.’来标识!】 -->
    <mappers>
        <mapper resource="com/yinghuo/mybatisStudy/dao/SubjectsDAOInterface.xml"/>
    </mappers>
</configuration>

SubjectDAOInterface.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yinghuo.mybatisStudy.dao.SubjectsDAOInterface">
    <!-- 配置查询 -->
    <select id="findAllSubjects">
        select * from subjects;
    </select>
</mapper>

注意事项

  • mybatis中,DAO的含义与Mapper相同。所以SubjectsDAO和SubjectMapper其意思相同,都代表实体类与数据库的交互。
  • mybatis的映射配置文件,如上面代码SubjectDAOInterface.xml必须与dao接口的包结构相同。(mybatis的映射配置文件在resources文件夹下,但其包结构也跟SubjectDAOInterface一样。)
  • 映射配置文件SubjectDAOInterface.xml中,<mapper>标签的属性namespace的取值必须为对应dao接口的全限定名。
  • 映射配置文件中,<mapper>中的子标签如:<select>,其id属性必须为接口的方法名。

有了上述四条事项中的后三条,我们就可以不用编写dao接口的实现类了,mybatis会帮我们编写。

dao功能的原始实现流程:

在一个类中的main函数体中:

public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        //1:获取配置文件流
        //import org.apache.ibatis.io.Resources;
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
        //2:创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3:用工厂创建SqlSession对象
        SqlSession ss = factory.openSession();
        //4:使用SqlSession对象创建dao接口的代理对象。
        SubjectsDAOInterface dao= ss.getMapper(SubjectsDAOInterface.class);
        //5:使用代理对象执行方法
        List<Subjects> subjects = dao.findAllSubjects();
        for(Subjects s:subjects) {
            System.out.println(s);
        }
        //6:释放资源
        ss.close();
        in.close();
    }

读取配置文件说明:无论是主配置文件中的DataSource的属性解析、还是映射配置文件中的sql语句与dao接口方法关联的解析,都是用到的一种解析方法:dom4j 解析xml技术

使用注解实现配置mapper:

​ 用注解代替映射文件。

  • 主配置文件中:(得到dao接口类的全限定名)

    • <mappers>中的<mapper resource="">子标签的属性改成<mapper class="",class里面是全限定名,包以'.'分隔。
  • dao接口代码中:(得到该接口类的方法名)

    • 增加注释:

      类中,方法前加:@Select("sql statement")

  • 编写@Select注释:(这步是自定义mybatis用到的

    • 首先设置该注释的生命周期和作用对象:

      注释体前加:@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)

    • 然后在注释体内,设置一个字符串接收sql语句(在dao接口方法前注释的@Select的值)

      String value();

mybatis实现思路:

自定义实现的项目:ubuntu--eclipse--mybatisCustom。

大体实现方法:

  • 1.通过xml解析工具,**解析主配置文件 **得到:
    • 连接所需参数信息
    • 映射配置文件(xml实现映射关联)
    • dao接口全限定类名(注解实现映射关联)
  • 2.在通过xml解析工具,解析映射配置文件或dao接口全限定名,得到:
    • 被代理方法的全限定名
    • sql statement(语句)
    • 承载类的全限定名(用于和数据库字段相对应的那个实体类)
  • 3.经第2步,已经得到了所有信息,然后是要实现动态代理和反射调用了(自定义一个实现了InvacationHandler的处理类,然后调用Proxy)。(这一步最麻烦,我没有成功,明明代码都一样,但是在invoke这一步,说参数类型不匹配,但是明明是匹配的。)
    • 建立连接Connection
    • 建立预处理语句,并发送执行。
    • 得到结果集,将结果集映射到承载类。
    • 返回代理对象。
1.jpg
2.jpg

mybatis 基础的CRUD

操作基本与前述类似。

如下,是配置映射文件:实现了基本的增查改删操作。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yinghuo.mybatisCRUD.dao.SubjectDAOInterface">

    <select id="findAll" resultType="com.yinghuo.mybatisCRUD.subject.Subjects">
        select * from subjects;
    </select>
    
    <select id="findOneById" resultType="com.yinghuo.mybatisCRUD.subject.Subjects" parameterType="INT">
        select * from subjects where id = #{id};
    </select>
    
    
    <insert id="saveOne" parameterType="com.yinghuo.mybatisCRUD.subject.Subjects">
        <!-- 保存后会反射,将当前数据库中id的值,映射到实体类的对应属性,若不加,则不会反射,id若没有初始化则为0 -->
        <selectKey keyProperty="id" keyColumn="id" resultType="INT" order="AFTER">
            select last_insert_id();
        </selectKey>
        INSERT into subjects(name,grade,enjoy) values(#{name},#{grade},#{enjoy});
    </insert>
    
    <delete id="deleteOneById" parameterType="java.lang.Integer">
        DELETE from subjects where id = #{id};
    </delete>
    
    <update id="updateOne" parameterType="com.yinghuo.mybatisCRUD.subject.Subjects">
        UPDATE subjects set name = #{name},grade=#{grade},enjoy=#{enjoy} where id=#{id}; 
    </update>
    
    <select id="findByName" resultType="com.yinghuo.mybatisCRUD.subject.Subjects" parameterType="String">
        select * from subjects where name like #{name};
    </select>
    
    <select id="findCounts" resultType="INT">
        select count(*) from subjects;
    </select>
</mapper>

标签

主配置文件中

注意:有顺序要求,否则会报错。如下依次。

(properties, settings, typeAliases, typeHandlers, objectFactory, objectWrapperFactor, reflectorFactory, plugins, environments, databaseIdProvider, mappers)

  • <configuration>:主标签,必须要命名空间才能用:<!DOCTYPE Configuration...>。后面的标签都属于本标签的子标签。

  • <environments>:用于包含多个配置环境。属性:default,设置一个默认的<environment>标签。

  • <environment>:用于单个环境配置。属性:id,来标识该环境配置标签。

  • <transactionManager>:事务管理标签。属性:type,指定事务管理器类型,一般是jdbc

    • 子标签:<property>:用来注入成员变量dataSource。
  • <dataSource>:用来配置数据源。属性:POOLED,表示连接池。

    • 子标签:多个<property>:用来配置连接信息:驱动、url、用户名、密码。
  • <properties>:用来指定外部properties文件。属性:resource,表示文件位置。

  • <typeAliases:用于配置包下所有类的别名。在mybatis中,由于预先设置了别名,如resultType="int"可以写成resulttype="INt"并不区分大小写

    当我们自己想这样使用的,可以用该标签。

    • 子标签:<typeAlias>:用于给某个指定类添加别名。
    • 子标签:<package:(*常用)用于给整个包下的所有类添加别名。属性:name="..."
      • 用处
      • ①用于给dao所在包在主配置文件添加别名,然后在映射配置文件中,就可以使用别名进行引用,而不用全限定名。
      • ②可以在<mappers>标签中,直接写<package name="dao接口所在位置">,可以替代<mapper class="..."><mapper resource="/../../";
dao接口映射配置文件中:
  • <mapper>:主标签。属性:namespace="path.to.daoInterface"

  • <select><insert><update><delete>:用于标识方法。

    属性:

    • id="method"
    • resultMap="resultMap的id"
    • resultType
    • parameterType="该方法参数类型"
  • <resultMap>:用于映射复杂的返回结果,如该实体类中引用别的对象,该实体类变量名与数据库中字段名不同等。

    子标签:

    • <id property="" column="">:用于主键映射。
    • <result property="" column="">:用于其他字段映射。
    • <association property="" javaType="">:用于一对一查询。
    • <collection property="" ofType="">:用于一对多查询。

属性:

  • id:辨识唯一标签

  • parameterType:当dao接口的方法需要参数时,使用该属性。value=全限定类名或者可以标识的名,如INT、int、string等

  • resultType:当该方法需要返回值时,用这个来标识返回值对象。value=全限定类名

OGNL表达式:(用于标签内sql语句的参数)

​ Object Graphic Navigation Language,对象图导航语言。

作用:通过对象的取值方法来获取数据。(写法上把get省略了)

​ 类中写法:user.getName();

​ OGNL写法:user.name

​ mybatis写法:name //因为在parameterType里面已经提供了类型,所以省略了类。此处写法的含 //义是在如<select ...>..here..</select>标签内部的语句,如:#{name}

对象参数:(通常用作对实体类对象的再包装,开发中,由多个对象组成一个查询条件类,来实现数据查 询)

​ 当类对象作为方法参数时,若要用对象的成员变量的属性,如Class Condition{ User user;},传入的 参数是Condition 对象,但要使用其中的user成员变量的属性(成员变量)user.name。此时写法为: #{user.name}

数据表字段与实体类属性不同时:

当数据库的字段名和实体类的成员变量名不一样时(当然最好一样),可以使用两种方式实现查询结果正常映射到实体类:

  • sql语句中修改:在如:<select ...> select * from subjects</subject> (运行效率更好)

    ​ 对应关系:id--myId、name--myName、grade--myGrade

    ​ 修改为:<select ...> select * id as myId,name as myName,grade as myGrade from

    subjects</subject>

  • 配置标签修改:可以通过<resultMap>标签修改:(开发效率稍高)

    <mapper>
      <resultMap id="subjectsMap" type="com.yinghuo.mybatis.subject.subjects">
          <!-- 主键修改 -->
          <id property="myId" column="id"/>
          <!-- 其余键修改 -->
          <result property="myName" column="name"/>
          <result property="myGrade" column="grade"/>
          <result property="myEnjoy" column="enjoy"/>
      </resultMap>
      
      <!-- 在对应的查询地方引用上面这个标签 -->
      <select id="findAll" resultMap="subjectsMap">
          select * from user;
      </select>
    <mapper>
    
配置properties文件

​ 可以在resourese文件夹下创建properties文件,其中有多个值,每个值为{key、Value}映射形式:name=sun。

主配置.xml文件使用properties文件

配置:通过在 Configuration 主标签下添加 <properties>标签,然后写 属性resource=" ''。其指为相对地址,如果放在resource下,则直接写文件名.properties。如:<properties resource="jdbcConfig.properties">

使用:然后在后面的子标签如<DataSource>中的子标签<property>,即可直接使用${key}来获得properties文件中的value的值。


mybatis 连接池配置

三种配置方式

  • 主配置文件中的<dataSource>标签

    属性type的取值:

    • ①POOLED :采用传统的javax.sql.DataSource规范(接口)中的连接池,mybatis有对其的实现类。

    • ②UNPOOLED :也是有实现了上述规范的实现类,但是没有连接池概念。连接是用时生成,关闭就真正销毁了。

    • ③ JNDI :采用服务器提供的 JDNI 技术实现,来获取DataSource对象,不同服务器能拿到的DataSource不一样。如 tomcat服务器采用dbcp连接池。

      注意:如果不是web或maven的war工厂,不能使用。

POOLED取连接过程:

概述:mybatis使用PooledDataSource 类来实现 java 的DataSource 规范,其内部步骤大概如下:

  • ①要新建连接时,看空闲池里是否有连接,若有,则取出一个返回。
  • ②若空闲池没有连接,则查看活跃池,若活跃池中连接数未达到最大数量,则新建一个连接,并放入活跃池,并返回。
  • ③若活跃池已达到最大数量,则从其中选择最先进来的(最老的)那个连接,进行适当加工,并返回。

Sql语句和映射配置文件

说明:查询语句有条件时,可以用配置文件中的标签进行辅助完成。

映射配置文件中:

下述都是在<select>标签的内部:

  • <where>:用了该标签,可以省略sql语句中的where 1=1(当多个与、或条件时),子标签<if>

  • <if>:属性为:test="condition"。用作条件语句,当不满足条件时,该标签内部的子标签和语句不会被执行。注意,条件语句中不能用&&、||,要用and、or代替

  • <foreach>:主要用于集合类型参数,配合实体封装类参数进行使用。

    属性:

    • collection:集合属性名
    • open:一般为:and id in(
    • close:一般为:)
    • item:该属性的值如:id,与内部相对应:#{id}。
    • separator:每个id中的分隔符:,

mybatis多表查询

步骤

①mysql中建立两个表(暂时以2代多)

②在项目中建立两个实体类、及其dao接口类

③配置两个dao接口的映射文件

④测试、实现配置

一对一:(包含多对一)

适用:①一对一对象;②一对多对象中,以”多“为主体,去包含唯一的“一”。

说明:通常是一对一的,如人和身份证。或者是用户和银行卡中,一张银行卡只能对应一个用户。

resultMap中标签:

  • <association>
    • 属性:javaType:填写类中引用对象的类型。

因为一对多,如一个study有多个subjects。但是一个subject只对应一个study,所以可以放在一起

<resultMap type="Subjects" id="UserSubjectsMap">
    <id property="id" column="id" />
    <result property="uid" column="uid"/>
    <result property="name" column="name" />
    <result property="grade" column="grade" />
    <result property="enjoy" column="enjoy" />
    <association property="user" javaType="user">
        <result property="name" column="uName" />
        <result property="sex" column="sex" />
        <result property="address" column="address" />
        <result property="city" column="city" />
    </association>
</resultMap>

<select id="findAll" resultMap="UserSubjectsMap">
        select s.*,u.name as uName,u.sex,u.address,u.city from subjects s,user u where u.id=s.uid;
</select>

一对多:

说明:如一个学生,有多门学科成绩。

resultMap中标签:

  • <collection>
    • 属性:ofType:填写集合中的元素类型,如list<E>中的E。

dao映射配置文件

    <resultMap id="userSubjectsMap" type="user">
        <!-- 主键映射 -->
        <id property="id" column="userId"/>
        <!-- 其余键映射 -->
        <result property="name" column="uName"/>
        <result property="sex" column="sex"/>
        <result property="city" column="city"/>
        <result property="address" column="address"/>
        <!-- 用于映射集合对象,像List -->
        <collection property="subs" ofType="Subjects">
            <id property="id" column="id"/>
            <result property="uid" column="uid"/>
            <result property="name" column="name"/>
            <result property="enjoy" column="enjoy"/>
            <result property="grade" column="grade"/>
        </collection>
    </resultMap>
    
    <select id="findAll" resultMap="userSubjectsMap">
        select u.id as userId,u.name as uName,s.*,u.sex,u.city,u.address from user u LEFT           JOIN subjects s on u.id=s.uid;
    </select>

注意:user是主表,subjects是从表。

多对多

项目:ubuntu -- eclipse -- mybatisMany4Many

说明:如一个用户,其可以多个爱好。而多个人,可以有同一个爱好。如此,用户库和爱好库则是多对多。

sql语句:(两表为例)

  • 首先需要一个中间表user-enjoy,其数据项为:另两表的主键(如id)。
  • 然后是sql语句形如:Select u.*,e.* from user u Left outer join user-enjoy ue on u.id=ue.uid LEFT OUTER JOIN enjoy e on e.id=ue.eid;

注意:编写sql语句中,多次将最后的条件子句中,别名写成了原名,这会报错。

下述代码:User 和 Role类,多对多查询。Role的dao接口省略。

    <resultMap id="userRoleMap" type="user">
        <!-- 主键映射 -->
        <id property="id" column="id"/>
        <!-- 其余键映射 -->
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
        <result property="city" column="city"/>
        <result property="address" column="address"/>
        <!-- 用于映射集合对象,像List -->
        <collection property="roles" ofType="Role">
            <id property="roleId" column="roleId"/>
            <result property="roleName" column="roleName"/>
            <result property="roleDesc" column="roleDesc"/>
        </collection>
    </resultMap>
    
    <select id="findAll" resultMap="userRoleMap">
        select u.*,r.* from user u left join user_role ur on ur.userId=u.id LEFT join role r on r.roleId=ur.roleId;
    </select>
    
    <select id="findOneById" resultMap="userRoleMap" parameterType="INT">
        select u.*,ur.*,r.* from user u,user_role ur,role r where ur.userId=u.id and u.id=${int} and ur.roleId=r.roleId; 
    </select>

JNDI

​ JNDI(Java Naming and Directory Interface,java命名和目录接口),是sun公司提供的一种标准的java命名系统接口。

​ 说明:其打包方式为war(web archive),用于网页应用。具体还是要找专门资料


mybatis缓存

延迟加载

问题:在一对多中,当我们有一个用户,他有100个账户,在查询用户的时候,要不要把关联的账户查出来?查询账户时,要不要把关联用户查出来?

  • 查用户时:应该延迟加载,即真正使用账户数据是才加载,不用的时候不查询。延迟加载也叫按需加载或懒加载。
  • 查账户时:可以立即加载。即不管用不用,只要一调用方法,马上发起查询。

四种表关系

一对多、多对多:通常使用延迟加载。

一对一、多对一:通常使用立即加载。

实现方式:无论是一对多还是多对一,其实都类似,就是在<resultMap>中的<association><collection>中,引用其他映射配置文件的<select>语句。

X对一:

步骤:

  • 首先,两个实体类已经有了,并且类中包含了对方的引用(成员变量)。

  • 然后,dao接口类中,都写好方法。

  • 在主配置文件中,显式开启延迟记载:

    <settings>
      <!-- 默认是关闭,需要显式开启延迟加载 -->
      <setting name="lazyLoadingEnabled" value="true"/>   
      
      <!-- 3.4.1以后,是默认false,可以不写。开启后,调用任何方法,就会马上加载属性。关闭后,则是按需加载 -->
      <setting name="aggressivelazyLoading" value="false"/>    
    </settings>
    
  • 在映射配置文件中:

    如:subject调用findAll时,不会加载user。只有用到时,才会通过<association ... select="...UserDAOInterface.findOneById">得到对应user对象。

    注意:此时<association>中,column属性不可省略了。 还有<properties><settings>似乎都有顺序要求(<configuraion>中)。放在其他位置会报错.

      <resultMap type="Subjects" id="UserSubjectsMap">
          <id property="id" column="id" />
          <result property="uid" column="uid"/>
          <result property="name" column="name" />
          <result property="grade" column="grade" />
          <result property="enjoy" column="enjoy" />
          <association property="user" javaType="user" column="uid"                   
              select="com.yinghuo.mybatisCRUD.dao.UserDAOInterface.findOneById"/>
      </resultMap>
    
      <select id="findAll" resultMap="UserSubjectsMap">
          select * from subjects;
      </select>
    
      <select id="findOneById" resultType="Subjects"  parameterType="INT">
          select * from subjects
          <where>
              id=#{id}
          </where>
      </select>
    
    
X对多:

实现:与X对一类似,区别:

  • <association>变成<collection>,及其内部的属性:javaType变成ofType
  • column="id",且在从表中,应该要有对应的字段,标识该数据属于主表中指定id的。
  • 还有一些就是SQL语句,和两个实体类结构的小问题了。

缓存

说明:内存用作数据库数据的缓存

适用:

  • 经常查询且不经常改变的
  • 数据正确与否对最终结果影响不大的

不适用:

  • 经常改变的数据(不可以使用写回的策略么?不行,因为可能存在多个线程或多台主机同时操作)
  • 数据的正确与否对最终结果影响很大的。(如:商品的库存、银行的汇率、股市的牌价)

mybatis中的一级、二级缓存

一级缓存:

说明:SqlSession对象里的缓存。(一级缓存是默认开启,不需要手动设置)

SqlSession在用户查询后,会缓存结果,形成一个Map结构,当再次查询同一个对象时,mybatis会先去查看是否SqlSession中是否有对应的值,如果有则返回,不需要再次访问数据库。

清空:

SqlSession.clearCache()

或者关闭sqlSession之后,再新建:ss=SqlSessionFactory.openSession();

SqlSession自动清空:

时机:当调用SqlSession的commit、update、insert的时候,会自动清空缓存。

注意:由于其机制,可能会导致缓存没有及时更新。如果并没有用该SqlSession进行更新、提交等操作,比如:

  • user = daoProxy.findbyone();
  • 暂停,并手动修改数据库信息。
  • user2 = daoProxy.findbyone();
  • user == user2 结果是true。因为他不会去访问数据库,user2是从缓存中提取的旧结果,并不是最新的数据。

二级缓存:

说明:SqlSessionFactory对象里的缓存。(需要手动设置开启)

SqlSessionFactory有一个公共缓存区,可以被其生成的任何SqlSession共享。只要一个SqlSession进行了Commit,就会将如查询得到的信息缓存在SqlSessionFactory内部。

当其新建或已建的SqlSession进行同样的查询时,就可以从其内部取数据,而不需要访问数据库。

开启:

默认是开启,设置地方:

  • 主配置文件:

    <settings>
      <setting name="cacheEnabled" value="true"/>
    <settings>
    
  • 使用dao映射配置文件.xml:

    <cache/>
    
    <!--然后在方法中声明使用缓存,下述返回值已使用了别名-->
    <select id="findAll" resultType="User" useCache="true">
          select  * from userx;
    </select>
    
  • 使用注解配置映射:

    ​ 注解dao接口,@CacheNamespace(blocking=true)即可。

注意

  • 得到的实体类对象的值是一样的,但是不同的对象,如obj1==obj2:false。
  • (*)只有其他SqlSession提交或关闭之后,才会缓存到SqlSessionFactory中,若没有提交,则没有缓存。

mybatis注解开发

说明:注解与映射文件配置(路径同于dao接口),仅可以存在一个。

大致开发步骤与普通一样,仅是主配置文件中,<mapper>配置的是dao接口的地址。

然后在dao接口中,注释方法,并传入sql语句。即可。

项目:ubuntu--eclipse--mybatisAnnotation

关于@Results、@ResultMap:

  • 当实体类名和数据库名不同时,如果不在sql中用别名,则需要配置映射,如下。

    @Select("select * from user;")
      @Results(id="userMap",value= {
              @Result(id=true,property="uid",column="id"),
              @Result(property="name",column="name"),
              @Result(property="sex",column="sex"),
              @Result(property="address",column="address"),
              @Result(property="city",column="city")
      })
       public List<User> findAll();
    
注解:
  • @Results:两个属性:id:唯一标识该Results; value:包含多个@Result注解,每个注解对应一个字段的映射。
  • @ResultMap:用于其他方法注解,引用一个@Results。其值标准格式为:value={"id1",”id2”...}

多表查询注解

多对一:

@Results()中,加入属性:@Result(property="",column="", one=@One(select="path.to.method", fetchType=FetchType.EAGER))

下面代码是UserDAOInterfaceUser实体类中包含成员变量Role role

@Select("select u.*,ur.roleId from user as u LEFT JOIN user_role as ur on u.id=ur.userId;")
    @Results(id="userMap",value= {
            @Result(id=true,property="uid",column="id"),
            @Result(property="name",column="name"),
            @Result(property="sex",column="sex"),
            @Result(property="address",column="address"),
            @Result(property="city",column="city"),
            @Result(property="role",column="roleId",javaType=Role.class,
                one=@One(select="com.yinghuo.mybatisAnnotation.                                                   dao.RoleDAOInterface.findOneById", fetchType=FetchType.EAGER)
                    )     
    })
public List<User> findAll();
多对多:

User实体类中包含成员变量List<Role> role

说明:在userDAOInterface中与多对一类似,区别:

  • @Select()中语句变为:@Select("SELECT * from user;")

  • one=@One(...)变成many=@Many(...)

  • @One()中,method变成...findByUserId;其根据user_role表,和user提供的id,对应找到user_role中所有的数据项,提取roleId返回role中的多个数据项。

  • 以下是RoleDAOInterface.findByUserId:

    @Select("SELECT r.* from role r,user_role ur where ur.userId = #{para} and ur.roleId=r.roleId;")
    List<Role> findByUserId(int userId);
    

缓存

说明:一级缓存是自动开启的。而二级缓存需要设置。


log4J

properties文档:(尽量放在resources下)

log4j.rootLogger=debug, stdout, R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log

log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=5

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n

\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014
\u7248\u6743\u58F0\u660E\uFF1A\u672C\u6587\u4E3ACSDN\u535A\u4E3B\u300C\u5C31\u662F\u4E8C\u4E8C\u4E8C\u4E8C\u5A77\u300D\u7684\u539F\u521B\u6587\u7AE0\uFF0C\u9075\u5FAA CC 4.0 BY-SA \u7248\u6743\u534F\u8BAE\uFF0C\u8F6C\u8F7D\u8BF7\u9644\u4E0A\u539F\u6587\u51FA\u5904\u94FE\u63A5\u53CA\u672C\u58F0\u660E\u3002
\u539F\u6587\u94FE\u63A5\uFF1Ahttps://blog.csdn.net/qq_34474324/article/details/98874675

错误收集

Result Maps collection does not contain value for ...

  • 说明:在映射配置文件中,有一个映射配置文件的select标签中属性resultType写成了resultMap
  • 解决方式:检查所有的配置映射文件(通常上述错误描述for后面,会标出该错误发生的dao接口,然后去该接口配置文件看),看看是不是有写错的。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容

  • 1.1mybatis下载 mybaits 的代码由github.com 管理,地址:https://github....
    暖熊熊阅读 861评论 0 5
  • mybatis学习记录 1.mybatis是什么 ​ mybatis是一款优秀的持久层框架,它支持定制化sql...
    一笑温阅读 290评论 0 0
  • 1、第一个Mybatis程序 思路:搭建环境->导入Mybatis->编写代码->测试 1.1搭建环境 搭建数据库...
    Darmonster阅读 636评论 0 0
  • MyBatis是一个优秀的持久层框架,它主要是完成对操作数据库的过程进行封装。它以xml或注解的方式将要执行的各种...
    当有和煦微风阅读 182评论 0 0
  • 目录 1. mybatis的基本概念 2. mybatis如何构建和执行的 3. mybatis的缓存 4. my...
    Java机械师阅读 765评论 0 0