2023-07-05 18:23:19

# mybatis笔记


核心:输入映射和输出映射


# 1 配置文件

新建java project 导入jar  写配置文件

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>
		<!-- <properties resource=""></properties> -->
		<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?useSSL=false" />
					<property name="username" value="root" />
					<property name="password" value="root" />
				</dataSource>
			</environment>
		</environments>
		
		<!-- 配置要加载的mapper.xml -->
		<mappers>
		 <mapper resource="sqlmap/UserMapper.xml"/>
		 
		</mappers>
	</configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
log4j.properties
	# Global logging configuration
	log4j.rootLogger=DEBUG, stdout
	# Console output...
	log4j.appender.stdout=org.apache.log4j.ConsoleAppender
	log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
	log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

	
	
		String resource="SqlMapConfig.xml";
		InputStream inputStream=Resources.getResourceAsStream(resource);
		SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
		SqlSession sqlSession=sessionFactory.openSession();
		
		//查找
		User user=sqlSession.selectOne("test.FindUserById",10);
		System.out.println("user= "+user);
		
		
		//更新 要指明id
		User user_update=new User();
		user_update.setId(20);
		user_update.setUsername("宋江2");
		user_update.setAddress("梁山2");
		user_update.setBirthday(new Date());
		user_update.setDetail("首领2");
		user_update.setScore(66.7f);
		user_update.setSex("1");
		sqlSession.insert("test.insertUser", user_update);
		sqlSession.commit();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
UserMapper.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="test">

		<!-- 根据用户id查询用户信息  编写statement
		parameterType:指定传入数据参数的类型
		resultType:映射生成的java对象类型,select查询结果集的列名要和resultType指定java对象的属性名保持一致才可以映射
		#{}:表示占位符,如果要传递简单类型数据,#{}可以写任意名称
		 -->
		 <select id="FindUserById" parameterType="java.lang.Integer"
		  resultType="com.mybatis.po.User">
		  SELECT * FROM USER WHERE ID=#{VALUE}
		 </select>
		 
		  <!-- 用户插入  传用户类型的对象(user), 传入的是user对象,#{}中写user对象的属性名  -->
		 <insert id="insertUser" parameterType="com.mybatis.po.User">
			<!-- 将自增主键返回到user对象
		  keyProperty:返回到user对象中的属性名
		 order:返回主键的时机
		 LAST_INSERT_ID:通过此函数获取自增主键值
		  -->
			<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
				SELECT LAST_INSERT_ID();
			</selectKey>
		 
			insert into user(username,birthday,sex,address,detail,score) values(
			#{username},#{birthday},#{sex},#{address},#{detail},#{score})
		 </insert>
		 
		 <!-- 删除 传入数据 java.lang.Integer -->
		 <delete id="deleteUserById" parameterType="java.lang.Integer">
			DELETE FROM USER WHERE ID=#{ID}
		 </delete>
		 
		 <!-- 更新  传入参数 com.mybatis.po.User -->
		 <update id="updateUser" parameterType="com.mybatis.po.User">
		 update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address},detail=#{detail},score=#{score}
		 where id=#{id}
		 </update>
	 </mapper>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?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>
	<!-- properties -->
	<properties resource="db.properties"></properties> 
	<!-- 自定义别名 -->
	<typeAliases>
	 <!--  <typeAlias type="com.mybatis.po.User" alias="user"/> -->
	 <!--批量别名定义,扫描整个包下的类 -->
	  <package name="com.mybatis.po"/>
	</typeAliases>
	
	<environments default="development">
		<environment id="development">
			<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>
	
	<!-- 配置要加载的mapper.xml -->
	<mappers>
		 <mapper resource="sqlmap/UserMapper.xml"/>
		 <!-- <mapper resource="sqlmap/mapper/UserMapper.xml"/> -->
		 
		<!-- 接口与xml文件名称一致,且在同一个目录。接口即mapper命名空间 -->
		<!-- <mapper class="com.mybatis.dao.mapper.UserMapper"/> -->
		
	    <!-- 注册指定包下的所有mapper接口。mapper接口和mapper映射文件名称相同且在同一个目录 -->
		<package name="com.mybatis.dao.mapper" />
	</mappers>
</configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 2 SqlSession

SqlSession
	SqlSession中封装了对数据库的sql操作,如:查询、插入、更新、删除等。
	通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

	SqlSessionFactoryBuilder
	SqlSessionFacoty是通过SqlSessionFactoryBuilder进行创建,SqlSessionFactoryBuilder只用于创建SqlSessionFactory,可以当成一个工具类,在使用时随时拿来使用不需要特殊处理为共享对象。

	SqlSessionFactory
	SqlSessionFactory是一个接口,接口中定义了openSession的不同方式,SqlSessionFactory一但创建后可以重复使用,实际应用时通常设计为单例模式。

	SqlSession
	SqlSession是一个接口,默认使用DefaultSqlSession实现类,sqlSession中定义了数据库操作。
	

namespace的作用(mapper接口地址即namespace,接口的方法即mapper的id,参数、返回值都相同)
	使用mapper接口不用写接口实现类即可完成数据库操作,简单方便,此方法为官方推荐方法。
	使用mapper接口调用必须具备如下条件:
	1、	Mapper接口方法名和mapper.xml中定义的每个sql的id相同
	2、	Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
	3、	Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
	4、	Mapper.xml文件中的namespace即是mapper接口的类路径。

	至此,mybatis的mapper包括mapper.xml和mapper接口两种文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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命名空间,接口方法即mapper的id。利用动态代理产生对象 -->
<mapper namespace="com.mybatis.dao.mapper.UserMapper">
<!-- sql片段,以表为单位进行抽取 -->
<sql id="query_user_where">
	<if test="ids !=null">
    		<!-- <foreach collection="ids" index="index" item="item" open="and id in(" 
    		separator="," close=")">
    	      #{item}
    		</foreach> -->
    		<foreach collection="ids" index="index" item="item" open="and (" 
    		separator="or" close=")">
    	      id=#{item}
    		</foreach>
	     	
    	</if>
      <if test="username !=null and username!=''">
    	  and username like '${username}%'
      </if>
      <if test="sex !=null and sex !=''">
      	 and sex=#{sex}
      </if>
      <if test="id >0">
      	 and id>#{id}
      </if>
</sql>
   
    <!-- 根据用户id查询用户信息  编写statement
    parameterType:指定传入数据参数的类型
    resultType:映射生成的java对象类型,select查询结果集的列名要和resultType指定java对象的属性名保持一致才可以映射
    #{}:表示占位符,如果要传递简单类型数据,#{}可以写任意名称
     -->
     <select id="findUserById" parameterType="java.lang.Integer"
      resultType="user">
      SELECT * FROM USER WHERE ID=#{VALUE}
     </select>
     
      <!-- 查询用户列表,根据用户名称模糊查询
     ${}:将传参数不加任何修饰将传的值拼接在sql中
      -->
     <select id="findUserList" parameterType="String" resultType="user">
    select * from user where username like '${value}%' 

     </select>
     
     <select id="findUserByUser" parameterType="user" resultType="user">
     <!-- 	select * from user where username like '${username}%' and sex=#{sex}  -->
     	select * from user
	     <where>
	     	<include refid="query_user_where"></include>
	     </where>
     </select>
     
       <!--   返回resultMap -->
     <select id="findUserResultMap" parameterType="user" resultMap="userListMap">
     	select username username_,sex sex_,birthday from user
     	<where>
     		<include refid="query_user_where"></include>
     	</where>
     </select>
     
     <!-- 定义resultMap -->
     <resultMap type="user" id="userListMap">
     	<id column="username_" property="username"/>
     	<result column="sex_" property="sex"/>
     	<result column="birthday_" property="birthday"/>
     </resultMap>
     
     <select id="findUserByMap" parameterType="hashMap" resultType="user">
     	select * from user where username like '${username}%' and sex=#{sex} 
     </select>
     
     <select id="selectUserCount" parameterType="user" resultType="int">
     <!-- 	select count(*) from user where username like '${username}%' and sex=#{sex}  -->
     select count(*) from user 
     <where>
     	<include refid="query_user_where"></include>
     </where>
     </select>
     
     <!-- 传入user,返回map -->
     <select id="findUserByUserReturnMap" parameterType="user" resultType="hashMap">
     	select * from user where username like '${username}%' and sex=#{sex}
     </select>
      <!-- 用户插入  传用户类型的对象(user), 传入的是user对象,#{}中写user对象的属性名  -->
     <insert id="insertUser" parameterType="com.mybatis.po.User">
        <!-- 将自增主键返回到user对象
      keyProperty:返回到user对象中的属性名
     order:返回主键的时机
     LAST_INSERT_ID:通过此函数获取自增主键值
      -->
     	<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
     		SELECT LAST_INSERT_ID();
     	</selectKey>
     
     	insert into user(username,birthday,sex,address,detail,score) values(
     	#{username},#{birthday},#{sex},#{address},#{detail},#{score})
     </insert>
     
     <!-- 删除 传入数据 java.lang.Integer -->
     <delete id="deleteUserById" parameterType="java.lang.Integer">
     	DELETE FROM USER WHERE ID=#{ID}
     </delete>
     
     <!-- 更新  传入参数 com.mybatis.po.User -->
     <update id="updateUser" parameterType="com.mybatis.po.User">
     update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address},detail=#{detail},score=#{score}
     where id=#{id}
     </update>
 </mapper>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

# 3 一对多查询

 <!-- user-orders 一对一查询,association -->
<resultMap type="com.mybatis.po.Orders" id="ordersUserMap">
	 <!-- id 是主键,不会重复。
	 即sql语句一对多会查询出id重复的语句
	 但是mybatis优化后,一对多的一当中的orderdetails的不会重复-->
	<id column="id" property="id"/>
	<result column="user_id" property="user_id"/>
	<result column="order_number" property="order_number"/>
	<!-- 一对一 association 使用javaType -->
	<association property="user" javaType="com.mybatis.po.User">
		<id column="user_id" property="id"/>
		<result column="username" property="username"/>
		<result column="sex" property="sex"/>
		<result column="birthday" property="birthday"/>
	</association>
</resultMap>

<!-- orders-orderdetail 一对多查询 -->
<resultMap type="com.mybatis.po.Orders" id="ordersUserOrderdetailResultMap" extends="ordersUserMap"> 
<!-- <resultMap type="java.util.LinkedHashMap" id="ordersUserOrderdetailResultMap">  -->
	<!-- 	
		一对多查询 。使用collection ofType
       property="orderdetails":关联查询的结果集存储在Orders上哪个属性。
	ofType="com.mybatis.po.Orderdetail":指定关联查询的结果集中的对象类型即List中的对象类型。 
	-->
	<collection property="orderdetails" ofType="com.mybatis.po.Orderdetail">
		<id column="orderdetail_id" property="id"/>
		<result column="item_id" property="item_id"/>
		<result column="item_num" property="item_num"/>
		<result column="item_price" property="item_price"/>
	</collection>
	
</resultMap>

<!-- Orders-Items 多对多 -->
<resultMap type="com.mybatis.po.Orders" id="ordersItemsResultMap"  extends="ordersUserMap"> 
	<!-- 	
		一对多查询 。使用collection ofType
       property="orderdetails":关联查询的结果集存储在Orders上哪个属性。
	ofType="com.mybatis.po.Orderdetail":指定关联查询的结果集中的对象类型即List中的对象类型。 
	-->
	<collection property="orderdetails" ofType="com.mybatis.po.Orderdetail">
		<id column="orderdetail_id" property="id"/>
		<result column="item_id" property="item_id"/>
		<result column="item_num" property="item_num"/>
		<result column="item_price" property="item_price"/>
		
		<!-- Orderdetail-Items 一对一 -->
		<association property="items" javaType="com.mybatis.po.Items">
		<id column="item_id" property="id"/>
		<result column="item_price_" property="item_price"/>
		<result column="item_name" property="item_name"/>
		<result column="item_detail" property="item_detail"/>
		</association>
	</collection>
</resultMap>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

# 4 缓存

<!-- 延迟加载 -->
<resultMap type="orders" id="oredersMap">
	<id column="id" property="id"/>
	<result column="user_id" property="user_id"/>
	<result column="order_number" property="order_number"/>
	<association property="user" javaType="user"
	select="com.mybatis.dao.mapper.UserMapper.findUserById" column="user_id"></association>
</resultMap>


	<!-- properties -->
	<properties resource="db.properties"></properties> 
	<!-- 延迟加载 -->
	<settings>
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>
	
	
二级缓存:
	二级缓存范围可以跨越session,在mapper.xml中同一个namespace范围使用二级缓存。

	配置:
	通过配置开启二级缓存。

	<!-- 开启二级缓存 -->
	<setting name="cacheEnabled" value="true"/>

	还需要在mapper.xml配置,表示要对该mapper.xml进行二级缓存。
	在mapper.xml配置:
	 <cache />

	对映射的pojo,实现序列化接口。
	应用场景(重点):	1、针对复杂的查询或统计的功能,用户不要求每次都查询到最新信息,使用二级缓存,通过刷新间隔flushInterval设置刷新间隔时间,由mybatis自动刷新。
	比如:实现用户分类统计sql,该查询非常耗费时间。
	将用户分类统计sql查询结果使用二级缓存,同时设置刷新间隔时间:flushInterval(一般设置时间较长,比如30分钟,60分钟,24小时,根据需求而定)
 
	2、针对信息变化频率高,需要显示最新的信息,使用二级缓存。
    将信息查询的statement与信息的增、删、改定义在一个mapper.xml中,此mapper实现二级缓存,当执行增、删、修改时,由mybatis及时刷新缓存,满足用户从缓存查询到最新的数据。
	比如:新闻列表显示前10条,该查询非常快,但并发大对数据也有压力。 
	将新闻列表查询前10条的sql进行二级缓存,这里不用刷新间隔时间,当执行新闻添加、删除、修改时及时刷新缓存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41