关于MyBatis2全程笔记

关于MyBatis2的重要笔记在下面的百度网盘连接中,欢迎大家一起学习
链接:https://pan.baidu.com/s/1zGAtbdQElMTgzUZUSg033w
提取码:2ywn

下面就我学习过程中的一些容易忘记的点再做一次记录,以便后续复习

第一步:编写mybatis配置文件

<?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>

	<!--导入db.properties配置文件————类路劲,表明这个文件就在resource下面-->
    <properties resource="db.properties"></properties>


	<settings>
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>    标准日志工厂,直接用就行-->
        <setting name="logImpl" value="LOG4J"/>      <!-- 需要配置,具体配置内容在下方 -->
    </settings>


    <!--起别名,这样resultType,paramType等不需要再去写对象对应的类路径,直接写类首字母小写即可-->
    <typeAliases>
        <!--给某一个具体的实体类起别名-->
        <typeAlias type="com.it.bean.User" alias="User1"></typeAlias>
        <!--把这个包里面的所有类都起了别名,别名为类名的首字母小写,大写也可以-->
        <package name="com.it.bean"/>
    </typeAliases>


    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <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>
    <!--<environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis2?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123"/>
            </dataSource>
        </environment>-->
    </environments>

    <!--每一个数据库接口对应的Mapper.xml都需要在这个配置文件中注册-->
    <mappers>
        <!--根据类路径,当和接口在一块时要写成com/it/dao/UserMapper.xml,就在resource下面就直接写-->
        <mapper resource="com/it/dao/UserMapper.xml"/>
        <!--根据包,这个包下面的所有接口都映射到,要求是配置文件要和接口名相同
        且位于同一目录下,因此要么和接口放一块,要么在resource下面创相同的文件夹再放置进去-->
        <package name="com.it.dao"></package>
        <!--总结:接口很多用包,接口不多一个一个写,毕竟这个不用同名,不用在同一路径-->
    </mappers>
    
</configuration>

第二步:编写MyBatis工具类

// 从 SqlSessionFactory 中获取 SqlSession
public class MyBatisUtil {

    private static SqlSessionFactory sqlSessionFactory;
    
    // 这是死的,必须要有
    static {
        // 使用Mybatis第一步:获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    
    // 获取SqlSession
    public static SqlSession getSqlSession(){
    	// 设置为true表示自动提交,不需要手动提交了
        SqlSession sqlSession = sqlSessionFactory.openSession(true);    // 用完了要记得关闭
        return sqlSession;
    }
}

第三步:编写数据库接口

这个按照具体的情况而自行编写

第四步:编写数据库接口对应的mapper.xml

这里要注意,数据库的接口肯定是放在java下面的包里面,而mapper习惯放到resource下面,这时要求mapper在resource下面的路径与接口在java中的路径一致
一个mapper接口对应一个mapper.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">

<!--namespace命名空间,绑定一个Mapper接口,为这个mapper接口的类路径-->
<mapper namespace="com.it.dao.UserMapper">

	<resultMap id="UserMap" type="user">
        <!--column数据库中的字段,property是javabean中的属性,一一映射,而且只需要把不一样的映射就好了-->
        <result column="pwd" property="password"></result>
    </resultMap>


    <!--select查询,id对应接口中的方法名字-->
    <select id="getUserList" resultMap="UserMap">
        select * from user;
    </select>


	<!--id————mapper接口中的某个方法名
		parameterType————参数类型
			* 当传递的参数只有一个可直接写
			* 当传递的参数有多个,可将其封装在map内部,取值时为#{key}
			* 当传递的参数为javabean对象时,取值直接为#{bean对象属性}
			* 当传递的参数为@param类型,则为#{id},一般多于一个没有用map时必须写@param
		resultType————返回值类型
			* 基本数据类型,则为_数据类型,如_int
			* 对象数据类型,则为首字母小写,如integer,string
			* 自己封装的javabean对象类型,由于起了别名,可直接写首字母小写的类名,这里要注意,这表明查询出来的数据库属性名要和javabean中的属性名要对应,名字要相同,不同的只会注入null,因此如果不同,就要使用到resultMap
			* List类型:resultType写List中元素的类型
            * Map类型:单条记录:resultType =map  多条记录:resultType=Map中value的类型-->
		sql语句中用#{}来取参数值
	-->
    <select id="getUserLike" parameterType="String" resultType="com.it.bean.User">
        select * from user where name like #{value};    
    </select>
  
    <insert id="addUser2" parameterType="Map">
        insert into user(id, name, pwd) values (#{id}, #{name}, #{pwd});
    </insert>
    
    <update id="updateUser" parameterType="com.it.bean.User">
        update user set name = #{name}, pwd = #{pwd} where id=#{id};
    </update>

    <delete id="deleteUserById" parameterType="Integer">
        delete from user where id=#{id};
    </delete>
</mapper>

第四步:测试

@Test
    public void testGetUserLike(){
        // 首先获得sqlSession对象
        SqlSession sqlSession = MyBatisUtil.getSqlSession();

        // 通过sqlSession获得对应接口对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserLike("%李%");
        for (User user : userList) {
            System.out.println(user);
        }
        
		// 所有的增删改是需要提交事务的
		// sqlSession.commit();

        // 关闭sqlSession
        sqlSession.close();
    }

补充

1、可能出现问题说明——Maven静态资源过滤问题
在pom.xml中加入这段代码就可以解决

	<build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include> </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

2、 @Param属性

接口所有的普通参数,尽量都写上@Param参数,尤其是多个参数时,必须写上!
• 有时候根据业务的需求,可以考虑使用map传递参数!
1、在接口方法的参数前加 @Param属性
2、Sql语句编写的时候,直接取@Param中设置的值即可,不需要单独设置参数类型

//通过密码和名字查询用户 
User selectUserByNP(@Param("username") String username,@Param("pwd") String pwd); 

 <select id="selectUserByNP" resultType="com.kuang.pojo.User"> 
	select * from user where name = #{username} and pwd = #{pwd}
 </select> 

3、配置log4j
首先编写log4j配置文件,在resource下面

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file


#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n



#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/java.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n



#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
在程序中使用Log4j进行输出!
//注意导包:org.apache.log4j.Logger static Logger logger = Logger.getLogger(MyTest.class);
	@Test 
	public void selectUser() { 
		logger.info("info:进入selectUser方法"); 
		logger.debug("debug:进入selectUser方法");
		logger.error("error: 进入selectUser方法"); 
		SqlSession session = MybatisUtils.getSession(); 
		UserMapper mapper = session.getMapper(UserMapper.class);
		List<User> users = mapper.selectUser();
		for (User user: users){
			System.out.println(user); 
		} 
		session.close(); 
	}

4、使用注解开发,由于注解开发的功能并不强大,往往mybatis是使用xml来进行开发的

5、分页方式——一般直接使用mysql种的limit标签,或者使用pageHelper插件,自行学习

6、多对一关系的处理,如多个学生对应一个老师,学生的javabean中有老师对象的属性
老师的javabean正常些数据库中的那几个属性,学生的不需要老师的id,直接给一个老师的对象

	// 学生关联一个老师
    private Teacher teacher;

查询时有两种方式:按查询嵌套处理和按结果嵌套处理,这里我只讲按结果嵌套处理

	<select id="getStudents2" resultMap="StudentTeacher2" >
        select s.id sid,
               s.name sname,
               t.id tid,
               t.name tname
        from student s,teacher t where s.tid = t.id
    </select>
    <resultMap id="StudentTeacher2" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <!--对于属性是对象的复杂类型,我们需要单独处理,这里对象用association,集合用collection
  		    property:注入给实体类的哪个属性
            javaType:把sql语句的查询结果封装给某个类的对象-->
        <association property="teacher" javaType="teacher">
            <result property="id" column="tid" />
            <result property="name" column="tname"/>
        </association>
    </resultMap>

7、一对多关系
如一个老师对应多个学生,此时学生的javabean正常写数据库中的属性,而老师的要多一个若干学生对象的集合

	// 一个老师拥有多个学生
    private List<Student> students;
	<select id="getTeacher" resultMap="TeacherStudent" parameterType="integer">
        select t.id tid, t.name tname, s.id sid, s.name sname
        from teacher t, student s where t.id = s.tid and t.id = #{tid};
    </select>
    <resultMap id="TeacherStudent" type="teacher">
        <result property="id" column="tid" />
        <result property="name" column="tname" />
        <!-- • JavaType是用来指定javabean中属性的类型
			 • ofType指定的是映射到list集合属性中javabean的类型 -->
        <collection property="students" ofType="student">
            <result property="id" column="sid" />
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

动态SQL——重点

写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。
那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。

插一句:使用UUID生成随机的id

public static String getId(){
    return String.valueOf(UUID.randomUUID()).replaceAll("-", "");
}
<select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>

    <!--choose标签类似于switch,只会选择一个满足的执行,从上到下选择一个-->
    <select id="queryBlogChoose" resultType="blog" parameterType="map">
        select * from blog
        <where>
            <choose>
                <when test="title != null">
                    and title = #{title}
                </when>
                <when test="author != null">
                    and author = #{author}
                </when>
                <otherwise>
                    and views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>


    <update id="updateBlogBySet" parameterType="map">
        update blog
        <set>
            /*sql片段复用*/
            <include refid="if_title_author"></include>
        </set>
        where id = #{id};
    </update>


    <!--定义sql片段,提高代码的可重用性,里面不要有where-->
    <sql id="if_title_author">
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </sql>

    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>

缓存

1、什么是缓存 [ Cache ]?
• 存在内存中的临时数据。
• 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
2、为什么使用缓存?
• 减少和数据库的交互次数,减少系统开销,提高系统效率。
3、什么样的数据能使用缓存?
• 经常查询并且不经常改变的数据。

MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存),与数据库同一次会话期间查询到的数据会放在本地缓存中。
 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。

一级缓存失效的四种情况
一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它;
一级缓存失效情况:没有使用到当前的一级缓存,效果就是,还需要再向数据库中发起一次查询请求!
1、执行了增删改操作,可能会改变原来的数据,所以系统必定会刷新缓存
2、sqlSession不同,我们的一级缓存是以sqlSession级别缓存,换了sqlSession肯定不一样了
3、sqlSession相同,但执行不同的数据,此时缓存里面没有这个数据,肯定失效
4、sqlSession相同,但手动执行清除一级缓存: sqlSession.clearCache();

二级缓存
• 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
• 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
• 工作机制
 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
 新的会话查询信息,就可以从二级缓存中获取内容;
 不同的mapper查出的数据会放在自己对应的缓存(map)中;
使用步骤
1、开启全局缓存 【mybatis-config.xml】

<setting name="cacheEnabled" value="true"/>

2、去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】

<cache/>

查出的数据都会被默认先放在一级缓存中
只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中

缓存顺序:
1、先看二级缓存中有没有
2、再看一级缓存中有没有
3、查询数据库

上一篇:Mybatis源码解析4——SqlSession


下一篇:从源码角度分析 MyBatis 工作原理