mybatis笔记

配置文件

mybatis-config 核心配置文件

一般放到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>

<!--    mybatis的标签是有顺序的 顺序为: -->
    <!-- properties?,settings?,typeAliases?,typeHandlers?,
    objectFactory?,objectWrapperFactory?,reflectorFactory?,
    plugins?,environments?,databaseIdProvider?,mappers? -->

<!--    一些变量为了方便改动 放入 "文件名.properties"中 使用时 导入 用${变量名}-->
    <properties resource="jdbc.properties"></properties>

    

    <settings>
    <!--    开启驼峰转换 
解决数据库_类型字段转为驼峰 如 user_name 与实体类userName 映射-->
        <setting name="mapUnderscoreToCamelCase" value="true" />
  <!--开启延时加载 按需加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="true"/>
    </settings>

    <typeAliases>
    <!--指定别名的三种方式 可不写 使用别名避免在***Mapper.xml中使用类的全路径-->
    
    <!--   1     挨个指定别名-->
    <!--        <typeAlias type="com.yan.pojo.User" alias="User"></typeAlias>-->
    
    <!--   2     类的默认简写名 ,默认为类名-->
    <!--        <typeAlias type="com.yan.pojo.User" ></typeAlias>-->
    
    <!--   3     整个包的默认类名为别名 -->
        <package name="com.yan.pojo"/>
        
    </typeAliases>

<!--    选择数据库开发环境 在default中 选择当前使用的环境 -->
    <environments default="development">

        <environment id="development">
    <!--            事务的管理方式:JDBC|MANGED   分别为 :执行sql使用JDBC原生的事务管理 事务提交、回滚需手动处理|被管理 如spring-->
            <transactionManager type="JDBC"/>

    <!--            数据源类型 POOLED|UNPOOLED|JNDI 分别表示 :POOLED:表示使用数据库连接池缓存数据库连接
                                                          UNPOOLED:表示不使用数据库连接池
                                                          JNDI:表示使用上下文中的数据源-->
            <dataSource type="POOLED">

    <!--             在sql5中 驱动类为com.mysql.jdbc.Driver   sql8驱动类为 com.mysql.cj.jdbc..Driver
                  同时注意  pom中 mysql-connector-java 与自己sql安装版本是否适配-->
                <property name="driver" value="${jdbc.driver}"/>

    <!--              在sql8中 url要带上时区 如 jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC-->
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
        
    <!--        另一个环境-->
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments> <!--引入映射文件-->

<!--    将各个接口Xxx 对应的XxxMybatis.xml文件引入核心配置文间中 有两种方式-->
    <mappers>
        
        <!--      1、  挨个加载配置文件 -->
        <!--       <mapper resource="mappers/UserMapper.xml"/>-->

        <!-- 2、以包为单位引入映射文件 要求:
                1、mapper接口所在的包要和映射文件所在的包一致
                2、mapper接口要和映射文件的名字一致 -->
        <package name="com.yan.mapper"/>

    </mappers>

</configuration>
接口Xxx对应的XxxMapper.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">

<!--    说明:

           1、查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射关系
            resultType:自动映射,用于属性名和表中字段名一致的情况
                一般指定别名在mybatis-config.xml 的<typeAliases>中  一般java类型都会有别名 如: java.lang.Integer->int|integer
                                java.lang.String ->string   Map->map     List->list   int->_int|_integer
	
            resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况


-->


<!--一个接口对应一个配置文件 -->

<!--   User getUserById(@Param("id")Integer id);-->
<mapper namespace="com.yan.mapper.UserMapper">



<!--    一个id对应一个一个接口中的方法 -->

<!--   User getUserById(@Param("id")Integer id);-->
<select id="getUserById" resultType="User">
    select *
    from t_user
    where id=${id};
</select>

<!--    List<Student> getAllStudent();-->
<!--多对一查询 属性的对象的属性对应数据库中查询的字段 -->
    <!--    级联查询-->
    <resultMap id="getUserMap" type="Student">

        <id property="sid" column="sid"></id>
        <result property="sname" column="sname"></result>
        <result property="myClass.cid" column="cid"></result>
        <result property="myClass.className" column="class_name"></result>
    </resultMap>
    <select id="getAllStudent" resultMap="getUserMap">
        select student.* ,class.*
        from t_student student
        left join t_class class
        on student.cid=class.cid
    </select>


</mapper>
mybatis的工厂类
public class GetSqlSession {
    static public SqlSession getSqlSession() throws IOException {
        
//        读取配置文件
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

//        SqlSessionFactoryBuilder 读取配置文件创造 sqlSessionFactory
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

//        工厂创造一个个具体的sqlSession  返回   
        
//        扩号内 true:事务自动提交 false:手动提交 最后执行 commit() 
       return  sqlSessionFactory.openSession(true);

    }
}

mybatis的使用
 @Test
    public void getUserById() throws IOException {

//     获取 SqlSession 传入接口类 通过框架找到 接口对应的mybatis.xml 接口不能调用方法 代理为一个类

        SqlSession sqlSession = GetSqlSession.getSqlSession();

        //        本质是找到接口对应的方法


        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //        调用方法 框架 读取xml中的sql语句
        User userById = mapper.getUserById(9);


        //        等同于
        //   UserMapper userById  = (UserMapper)GetSqlSession.getSqlSession().selectOne("com.yan.mapper.UserMapper.getUserById",9);

        //        未开启自动事务的情况下
        //        sqlSession.commit();

        System.out.println(userById);
    }

#{} 与${}

  • mybatis的本质对JDBC的封装 要将先xml中的语句转为普通的JDBC能够识别的sql语句再去执行

    #{} 转为的占位符 ?默认会给值加'' jdbc的prepareStatement 一般情况使用#{}
    ${} 转为字符串拼接的方式 默认不会给值加'' jdbc的statement
    二者可在一个sql混用

1. #{}:
<!--   User getUserById(@Param("id")Integer id);-->
<select id="getUserById" resultType="User">
    select *
    from t_user
    where id=#{id};
</select>
	
**要转为**

![在这里插入图片描述](https://img-blog.csdnimg.cn/376ff6e576be4d5a8c98b8f5a4143a25.png)
等同于
Connection con = getCon();
 String sql="select *from t_user where id=?";
 PreparedStatement prepareStatement = con.prepareStatement(sql);
 prepareStatement.setString(1,9);
2. ${}
```xml
<select id="getUserById" resultType="User">
    select *
    from t_user
    where id=${id};
</select>

```
**转化为**

在这里插入图片描述
等同于

Connection con = getCon();
	        Statement statement = con.createStatement();
	        String sql="select *from t_user where id="+id;
	        ResultSet resultSet = statement.executeQuery(sql);

xml中sql语句获取参数值5种情况

1. 单个参数

${}和#{}以任意的名称获取参数的值**
例:


<!--   User getUserById(Integer id);-->

<select id="getUserById" resultType="User">
    select *
    from t_user
    where id=${aaaaaa};
    ${}或#{}的参数为任意 若是变量是字符串 记得${}加上''
</select>
2. 多个参数

MyBatis会自动将这些参数放在一个map集合中,以arg0(注意0开始),arg1…为键,以参数为值;以param1,param2…(注意1开始)为键,以参数为值;因此只需要通过${}和#{}访问map集合的键就可以获取相
对应的

例:

<!--    User getUserByIdAndName(Integer id,String username);-->

    <select id="getUserByIdAndName" resultType="User">
        select *
        from t_user
        where id=#{arg0}
        and username=#{arg1};
    </select>
变量arg 不能拼错 顺序固定 (第一个参数为0,第二个为1...

<!--    User getUserByIdAndName(Integer id,String username);-->
    <select id="getUserByIdAndName" resultType="User">
        select *
        from t_user
        where id=#{param1}
        and username=#{param2};
    </select>

变量param 不能拼错 顺序固定 (第一个参数为1,第二个为2...
3. 参数为map类型

sql语句中 #{}或${}的变量为map的key(不能再用arg0…或param1…)

例:

<!--    User getUserByIdAndNameMap(Map<String, Object>map);-->
    <select id="getUserByIdAndNameMap" resultType="user">
        select *
        from t_user
        where id=#{id}
          and username=#{username};
    </select>

	@Test
    public void getUserByIdAndName() throws IOException {
        UserMapper mapper = GetSqlSession.getSqlSession().getMapper(UserMapper.class);

        HashMap<String, Object> map = new HashMap<>();
        map.put("id",9);
        map.put("username","wyy");
        System.out.println(mapper.getUserByIdAndNameMap(map));
    }
4. 参数为实体类对象

${}和#{} 中为对象中属性名

mybatis 会通过实体类get方法查询他们对应的值
所以 用实体类做变量要有 getter ;用实体类接收查询结果要有 setter

例:

<!--    int InsertUser(User user);-->
    <insert id="InsertUser">
        insert into t_user values (null ,#{username},#{email});
    </insert>


 @Test
    public void getUserByIdAndName() throws IOException {
        UserMapper mapper = GetSqlSession.getSqlSession().getMapper(UserMapper.class);
        User user = new User();
        user.setUsername("admin000");
        user.setEmail("qq");
        System.out.println(mapper.InsertUser(user));
    }
5. 使用@Param()

@Param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,以@Param()注解中的value属性值
为#{}或${}中的值
(param1, param2…也适用 但arg0,arg1…不适用)
例:

<!--    User getUserByIdAndName(@Param("id")   Integer id,@Param("name") String username);-->

    <select id="getUserByIdAndName" resultType="User">
        select *
        from t_user
        where id=#{id}
        and username=#{name};
    </select>

查询多条map集合的数据的两种方式

查询没有映射实体类的数据就要用map 一次查询多条没有实体类映射的数据就要一次返回多条map

  1. map的集合 list<map<String,Object>>

例:

<!--    List<Map<String,Object>>getUserMap();-->

    <select id="getUserMap" resultType="map">
        select * from t_user
    </select>

结果样式:

[{id=9, email=we, username=wyy}, {id=10, email=qq, username=admin000}]
  1. 使用@MapKey(“返回大map包裹小map要使用的key”)
    最终要以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的 map集合

例:
接口:

 @MapKey("id") 使用t_user的key作为key
 
   Map<String,Object> getUserMap();

xml:

 <select id="getUserMap" resultType="map">
        select * from t_user
 </select>

结果样式:

{9={id=9, email=we, username=wyy}, 10={id=10, email=qq, username=admin000}}

模糊查询的三种方式

1. 使用 ‘%${}%’

利用${}的拼接进去

<!--     User getUserByMoHU(@Param("username")String username);-->
    <select id="getUserByMoHU" resultType="User">
        select *
        from t_user
        where username
        like '%${username}%'
    </select>

2. 使用concat(‘%’,#{username},‘%’)
<!--     User getUserByMoHU(@Param("username")String username);-->
    <select id="getUserByMoHU" resultType="User">
        select *
        from t_user
        where username
        like concat('%',#{username},'%')

    </select>
3. 使用"%“#{}”%"
<!--     User getUserByMoHU(@Param("username")String username);-->

    <select id="getUserByMoHU" resultType="User">
        select *
        from t_user
        where username
        like "%"#{username}"%"

    </select>

in 型操作使用${}

例:删除

<!--    int delMOre(@Param("ids") String ids);-->
    <delete id="delMOre">
        delete
        from t_user
        where id in (${ids});
    </delete>

例:查询:

<!--    int delMOre(@Param("ids") String ids);-->
   <select id="getAllUser" resultType="User">
       select *
       from t_user
        where username
        in (${names})

   </select>

动态设置表名 要使用${}

<!--    List<User> getUser(@Param("userTable") String userTable);-->
    <select id="getUser" resultType="User">
        select *
        from ${userTable};
    </select>

获取自增主键

在插入数据的同时 能查询到数据库中为其分配的自增id值

例:

<!--    int InsertUser(User user);-->
<!--    keyProperty :获取到的id保存到对象的那个属性 useGeneratedKeys: 开启获取主键 -->
    <insert id="InsertUser" useGeneratedKeys="true" keyProperty="id">
        insert into t_user values (null ,#{username},#{email});
    </insert>

在这里插入图片描述

解决实体类字段与数据库字段不同的两种方法

1. 在sql语句中通过 as 起别名

例:

在这里插入图片描述

<!--    List<User> getUser();-->
    <select id="getUser" resultType="User">
        select uid as id,name as username
        from user
    </select>
2. 通过resultMap
<!--    List<User> getUser();-->
<!--    id 给下方resultMap绑定  type:进行映射的实体类-->
    <resultMap id="userMap" type="User">
<!--        id 属性使用id标签-->
        <id column="uid" property="id"></id>
        
<!--        其余属性使用result标签-->
        <result column="name" property="username"></result>
    </resultMap>
    
    <select id="getUser" resultMap="userMap">
        select * from user
    </select>

多对一 (多表一对一也适用)3种方式

如 学生表 班级表

多个学生对应一个班级 在学生实体类中 班级为对象
student 表

 	private Integer sid;
 	
    private String sname;

    private Integer cid;

// 班级类对象
    private MyClass myClass;

一个班级对应多个学生 在班级实体类中 学生为list集合对象

class 表

 	private  Integer cid;
    
    private String className;
    //对应多个学生属性
    private List<Student> students;

查询一个学生的详细信息 包括自身属性和班级信息 而学生中的班级对象属性是无法赋值的 查询出来班级的数据要给学生属性班级对象的对应属性赋值

1. 级联方式处理映射关系

属性中对象的属性对应数据库中字段

<!--    List<Student> getAllStudent();-->

    <resultMap id="getStudentMap" type="Student">

        <id property="sid" column="sid"></id>
        <result property="sname" column="sname"></result>
        <result property="myClass.cid" column="cid"></result>
        <result property="myClass.className" column="class_name"></result>
    </resultMap>
    <select id="getStudentMap" resultMap="getUserMap">
        select student.* ,class.*
        from t_student student
        left join t_class class
        on student.cid=class.cid
    </select>
2. 使用association处理映射关系
    <!--    List<Student> getAllStudentAssociation();-->
<!--    类似于 嵌套了一个映射 第一层:属性对应的字段 第二层:属性中对象的属性对象的子段-->
    <resultMap id="getStudentMapAss" type="Student">
        <id column="sid" property="sid"></id>
        <result column="sname" property="sname"></result>

    <!--     association   处理实体类类型属性  注意javaType是设置对象属性的类型-->
        <association property="myClass" javaType="MyClass">

            <!--            映射关系-->
            <id column="cid"  property="cid"></id>
            <result column="class_name" property="className"></result>

        </association>
    </resultMap>

    <select id="getAllStudentAssociation" resultMap="getStudentMapAss">
        select student.*,class.*
        from t_student student
        left join t_class class
        on student.cid=class.cid
    </select>

1. 分步查询
		 1.先查询学生所有信息
		  studentMapper.xml:
	<!--    List<Student>  getStudent();-->

   <resultMap id="getStudentMap" type="Student">
       <id column="sid" property="sid"></id>
       <result column="sname" property="sname"></result>
       <result column="cid" property="cid"></result>
       
<!--        要根据查询出的cid 调用ClassMapper的方法去根据cid查询出班级信息 返回拼接成完整信息-->
<!--        select:分步查询第二步的接口地址   column:要向接口中传递的数据是从数据库哪个字段中的数据-->
        <association property="myClass" select="com.yan.mapper.MyClassMapper.getClassByCid" column="cid"></association>
     </resultMap>
     
	<select id="getStudent" resultMap="getStudentMap">
	        select *
	        from t_student
	    </select>

		2. 根据学生信息中的cid去查询对应班级信息 最后进行组合即可查出所有详细信息
		classMapper.xml
<!--    MyClass getClassByCid(@Param("cid") Integer cid);-->

    <select id="getClassByCid" resultType="MyClass">
        select *
        from t_class
        where cid=#{cid}
    </select>

三种查询结果样式:另一个类包含在对象属性中

[Student{sid=1, sname='xiaoming', cid=1, myClass=MyClass{cid=1, className='班级1', students=null}}, Student{sid=2, sname='小红', cid=1, myClass=MyClass{cid=1, className='班级1', students=null}}]

一对多

与多对一不同的是 查询回来的是一个对象集合 一个集合不能点属性 没有级联查询
查询一个班级对应的所有学生

1. 使用collection 处理映射关系
对应上面多对一第二种方法  注意将**association->collection ,javaType->ofType**
<!--    List<MyClass> getAllClass();-->
    <resultMap id="getAllMap" type="MyClass">
        <id property="cid" column="cid"></id>
        <result property="className" column="class_name"></result>


        <collection property="students" ofType="Student">
            <id column="sid" property="sname"></id>
            <result column="sname" property="sname"></result>
        </collection>
     </resultMap>
        <select id="getAllClass" resultMap="getAllMap">
            select *
            from t_class
            left join t_student
            on t_class.cid=t_student.cid
    
        </select>
2. 分步查询

与多对一只有association->collection 不同

	1. 先去获取班级全部信息
			MyClassMapper.xml
			

```xml
<!--    List<MyClass> getAllClass();-->
<resultMap id="getAllMap" type="MyClass">
    <id property="cid" column="cid"></id>
    <result property="className" column="class_name"></result>
    <collection property="students" select="com.yan.mapper.StudentMapper.getAllStudentByCid" column="cid"></collection>

 </resultMap>
    <select id="getAllClass" resultMap="getAllMap">
        select *
        from t_class
        left join t_student
        on t_class.cid=t_student.cid

    </select>
```





	2. 再由班级编号去学生表查询对应学生
			studentMapper.xml
		
```xml
<!--    List<Student> getAllStudentByCid(@Param("cid")Integer cid);-->
<select id="getAllStudentByCid" resultType="student">
    select *
    from t_student
    where cid=#{cid}
</select>
```

分步查询思路
先去获取当前属性,对于对象属性在通过另一个条件查询 条件就在当前查询出的属性中
在xml绑定语句 指定条件
分步查询优点
实现懒加载 例如:在查询一个学生信息时 时如不需要class的数据 将不执行第二条sql语句

前提:
在myabtis-config.xml中统一配置

 <!--开启延时加载 按需加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="true"/>

或单独配置 在<association fetchType="lazy"><collection fetchType="lazy">
fetchType="lazy(延迟加载)|eager(立即加载)

一对多,多对一 补充:

注意sql语句左连接与右连接区别

左连接 交集和非交集
在这里插入图片描述
右连接:只有交集
左连接

动态sql

1. where if

动态添加where :如果if都不满足 省去where ;可省略(或补上)if语句中前方的and

例:根据不确定个条件查询user

不使用where

<!--    List<User> getUserBy(@Param("id")Integer id,@Param("username") String username,@Param("email")String email);-->

<select id="getUserBy" resultType="User">
        select *
        from t_user
        where 1=1
          
        <if test="username!='' and username!=null">
            and username=#{username}
        </if>
        <if test="email!='' and email!=null">
            and email=#{email}
        </if>

        <if test="id!='' and id!=null">
            and id=#{id}
        </if>
    </select>

使用where

<!--    List<User> getUserBy(@Param("id")Integer id,@Param("username") String username,@Param("email")String email);-->

	<select id="getUserBy" resultType="User">
        select *
        from t_user
        <where>
	        <if test="username!='' and username!=null">
	            username=#{username}
	        </if>
	        <if test="email!='' and email!=null">
	            email=#{email}
	        </if>
	
	        <if test="id!='' and id!=null">
	             id=#{id}
	        </if>
        </where>
	</select>
2. trim

trim用于去掉或添加标签中的内容
常用属性:

  • prefix:在trim标签中的内容的前面添加某些内容
  • prefixOverrides:在trim标签中的内容的前面去掉某些内容
  • suffix:在trim标签中的内容的后面添加某些内容
  • suffixOverrides:在trim标签中的内容的后面去掉某些内容
3. choose下的 when(if else if )、otherwise(else)
  • choose下只能有一个语句被选中

  • otherwise相当于else 不出现 或只在末尾出现一次
    例:

<!--    List<User> getUserBy(@Param("id")Integer id,@Param("username") String username,@Param("email")String email);-->
    <select id="getUserBy" resultType="User">
        select *
        from t_user
        <where>
            <choose>
                <when test="id!='' and id!=null">
                    id=#{id}
                </when>
                <when test="username!='' and username!=null ">
                    username=#{username}
                </when>
                <otherwise>
                    id=15
                </otherwise>
            </choose>
            </where>
    </select>
4. foreach循环部分sql语句

要注意循环体内对象要加上#{}包裹
例 批量添加:

<!--    int addUserMore(@Param("Users") List<User> users);-->
<!--    collection:从接口接收过来的值   item:每一项 separator:每次循环的分隔符 -->
    <insert id="addUserMore">
        insert into t_user
        values   
        <foreach collection="users" item="user" separator=",">
           ( null,#{user.username},null)
        </foreach>
    </insert>

转变成jdbc形式是

insert into t_user values ( null,?,null) , ( null,?,null) , ( null,?,null)

例批量删除

<!--    int delByIds(@Param("ids") Integer[] ids);-->
    <delete id="delByIds">
        delete
        from t_user
        where id
        in
    --         open:在整体的循环前面加上  close :在整体循环后面加上 
        <foreach collection="ids" separator="," item="id" open="(" close=")">
            #{id}
        </foreach>
    </delete>
5. sql片段 +include去引用

相当于将常用的sql部分片段定义为一个常量 在sql语句中去引用增加sql部分代码通用性
例: 原形式:

<!--    List<User> getUser();-->
    <select id="getUser" resultType="User">
        select id,username from t_user
    </select>

使用<sql>改造后

	<sql id="idAndUsername">
	    id,username
	</sql>
<!--    List<User> getUser();-->
    <select id="getUser" resultType="User">
        select <include refid="idAndUsername"></include> from t_user
    </select>

一、二级缓存

1. 一级缓存

一级缓存默认开启,是sqlSession级别的 (只有同一个sqlSession才有效)

测试:
注意 同一个session下 连着相同查询 第二次没有访问数据库直接返回结果
在这里插入图片描述

缓存不可用两种情况:
	1. 不同的session 虽是相同的查询但不同的session去调用依然不可用 但之前的缓存还在

在这里插入图片描述

	2. 同一个session 调用不同的语句 即使sql语句相同 也不能使用缓存

在这里插入图片描述

缓存清空两种情况:

· 1. 两次相同的查询有之间有任何一次对表的增删改(即使没有修改成功)

·在这里插入图片描述

2. 手动清除 sqlSession.clearCache()

在这里插入图片描述

2. 二级缓存

二级缓存需要手动开启,作用于整个sqlSessionFactory级别 要保证是同一个sqlSessionFactory提供
二级缓存开启数据会现从二级中查找,再去一级缓存,最后数据库

二级缓存使用方式
  1. 在mybatis-config.xml中 设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
  2. 在xxxMaper.xml中 添加<cache/>
  3. 在使用时 必须将seesion关闭才生效 sqlSession.close();
  4. 用到的实体类必须序列化 implements Serializable

在测试过程中发现 使用这种工具类 每次获取一个seqlSession都会创建一个sqlSessionFactory 无法保证 是同一个sqlSessionFactory提供

 static public SqlSession getSqlSession() throws IOException {

//        读取配置文件
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

//        SqlSessionFactoryBuilder 读取配置文件创造 sqlSessionFactory
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);

//        工厂创造一个个具体的sqlSession  返回

//        扩号内 true:事务自动提交 false:手动提交 最后执行 commit()
       return  sqlSessionFactory.openSession(true);


    }

测试
不同的sqlSession调用同一个接口

  @Test
    public void selectUser() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//        同一个工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

//        创建两个sqlSession
        SqlSession sqlSession1 = sessionFactory.openSession(true);
        SqlSession sqlSession2= sessionFactory.openSession(true);

        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);

        System.out.println(mapper1.selectUser());

//        一定要提交sqlSession
        sqlSession1.close();
        System.out.println(mapper2.selectUser());

        sqlSession2.close();
    }

在这里插入图片描述

使得二级缓存清空只能是 在此期间发生对表的修改(sqlSession.clear()无效)

在这里插入图片描述
补充
在cache中可选缓存策略 <cache/>
eviction属性:缓存回收策略,默认的是 LRU。

  • LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO(First in Firstout) – 先进先出:按对象进入缓存的顺序来移除它们。
整合第三方二级缓存EHCache

使用步骤:

  1. 导入依赖:
<dependency> 
	<groupId>org.mybatis.caches</groupId>
	<artifactId>mybatis-ehcache</artifactId>
	<version>1.2.1</version>  					    
</dependency>


  1. 创建Ehcache配置文件ehcache.xml(文件名固定)
<?xml version="1.0" encoding="utf-8" ?> 
	<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 			xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> 
	<!-- 磁盘保存路径 --> 
	<diskStore path="D:\ehcache"/> 
	<defaultCache 
		maxElementsInMemory="1000" 
		maxElementsOnDisk="10000000" 
		eternal="false" 
		overflowToDisk="true" 
		timeToIdleSeconds="120" 
		timeToLiveSeconds="120" 
		diskExpiryThreadIntervalSeconds="120" 
		memoryStoreEvictionPolicy="LRU"> 
	</defaultCache> 
</ehcache>
  1. 将XxxMapper.xml 中的cache标签设置为
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

引入对应日志(原来日志不能打印)
1. pom文件

  <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
 </dependency>
  1. 创建logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 指定日志输出的位置 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

        <encoder>

            <!-- 日志输出的格式 -->
            <!-- 按照顺序分别是: 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
        </encoder> </appender>
    <!-- 设置全局日志级别。日志级别按顺序分别是: DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="info">
        <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->

        <appender-ref ref="STDOUT" />

    </root>
    <!-- 根据特殊需求指定局部日志级别 -->
    <logger name="com.yan.mapper" level="DEBUG"/> </configuration>

代码上没有变化 效果相同
在这里插入图片描述

mybatis逆向工程(由数据库生成java模板代码

根据配置的数据库表自动生成pojo实体类、mapper接口、Mapper.xml
使用方式:

  1. 在pom文件中引用插件
<build> 
<!-- 构建过程中用到的插件 -->
	<plugins> 
 <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
		<plugin> 
		<groupId>org.mybatis.generator</groupId> 
		<artifactId>mybatis-generator-maven-plugin</artifactId> 
		<version>1.3.0</version> 
		<!-- 插件的依赖 --> 
		<dependencies> 
		<!-- 逆向工程的核心依赖 --> 
			<dependency> 
				<groupId>org.mybatis.generator</groupId> 
				<artifactId>mybatis-generator-core</artifactId> 
				<version>1.3.2</version> 
			</dependency> <!-- MySQL驱动 --> 
			<dependency> 
				<groupId>mysql</groupId> 
				<artifactId>mysql-connector-java</artifactId> 
				<version>8.0.16</version> 
			</dependency> </dependencies> 
		</plugin>
	</plugins>
</build>
  1. 创建逆向工程的配置文件generatorConfig.xml(文件名写死)如下:
  2. 点击对应maven插件,自动生成
1. 简化模板

在mapper中只提供了5种操作
主要作用是根据表创建对应结构,业务仍需自己写sql在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>



    <!-- targetRuntime: 执行生成的逆向工程的版本
        MyBatis3Simple: 生成基本的CRUD(清新简洁版)
        MyBatis3: 生成带条件的CRUD(奢华尊享版) -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">

        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"
                        userId="root"
                        password="1234">
        </jdbcConnection>

<!--        targetPackage     指定生成的model生成所在的包名-->
<!--        targetProject     指定在该项目下所在的路径-->

        <!-- Pojo的生成策略-->
        <javaModelGenerator targetPackage="com.yan.pojo"
                            targetProject=".\src\main\java">

            <!-- 是否允许子包 -->
            <property name="enableSubPackages" value="true"/>
<!--             是否对类CHAR类型的列的数据进行trim操作 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- mapper的生成策略 -->
        <sqlMapGenerator targetPackage="com.yan.mapper"
                         targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <!--  xml-->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.yan.mapper"
                             targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>


        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_user" domainObjectName="Userqwqw"/>
    </context>
</generatorConfiguration>
2. 标准模板

采用了MBG风格 提供了大量的封装sql的方法 简单业务只需要调用方法
<context id="DB2Tables" targetRuntime="MyBatis3Simple">中的MyBatis3Simple 替换成 MyBatis3 重新点击创建

相较于简易型在pojo多了 Example用于向mapper中传递条件
例:

  @Test
    public void getTest() throws IOException {
        TestMapper mapper = GetSqlSession.getSqlSession().getMapper(TestMapper.class);

//        example中封装了条件
        TestExample example = new TestExample();
        example.createCriteria().getAllCriteria();

//        在mapper中传入条件
        System.out.println(mapper.selectByExample(example));

    }

例:
生成的pojo没有有参构造函数

   @Test
    public void getTest() throws IOException {
        TestMapper mapper = GetSqlSession.getSqlSession().getMapper(TestMapper.class);

//        example中封装了条件
        TestExample example = new TestExample();
//        条件为:name为aa 并且id为1 或者name为bb  注意 or() 使用要换行
        example.createCriteria().andNameEqualTo("aa").andIdEqualTo(1);
        example.or().andNameEqualTo("bb");

//        在mapper中传入条件

//        修改的两种方式
        
// 1、       只有指明的地方才会修改,其余保持不变
        mapper.updateByExampleSelective(new com.yan.pojo.Test(100,"cc"),example);
        
// 2、      指明的修改,其余修改为null
//        mapper.updateByExample(new com.yan.pojo.Test(100,"cc"),example);
    }

分页插件

有了分页插件 ,返回分页信息更细致 ,分页查询更方便
插件会拦截数据库请求 ,加上limit 所以注意xml中sql语句写完不要加;
在所有查询结果中截取

使用

  1. 带入pom依赖
 	 <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.0</version>
      </dependency>
  1. 在mybatis-config.xml的 <environments >标签上方导入
 	<plugins>
        <!--设置分页插件-->
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

测试:

@Test
    public void getUser() throws IOException {
        UserMapper mapper = GetSqlSession.getSqlSession().getMapper(UserMapper.class);
//      开启分页 自动获取查询数据
        Page<Object>page =PageHelper.startPage(2,3);

        List<User> users = mapper.selectUser();

//        users已经在page中
        System.out.println(page);


//        PageInfo 放在查询后面 数据更加详细

//        第二个参数,显示有几个的页码的数据
        PageInfo<User> pageInfo = new PageInfo<>(users, 2);
        System.out.println(pageInfo);


    }
变量说明:

pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值