MyBatis

一,入门程序

需求:
1、根据用户id查询用户信息
开发步骤:
1.建立工程
2.导入所需jar包
3.创建po
4.创建SqlMapConfig.xml 随便取 今天我们放在config下
5.创建User.xml sql语句都定义在这文件下
6.在 SqlMapConfig.xml 文件中配置 User.xml
7.测试
8.创建log4j.properties

2、根据用户名称模糊查询用户列表
只需要编写
5.创建User.xml sql语句都定义在这文件下
7.测试

3、添加用户
只需要编写
5.创建User.xml sql语句都定义在这文件下
7.测试

示例1:根据用户id查询用户信息

1,建立一个webproject工程
2,导入所需jar包

在这里插入图片描述
3,创建po
所谓po可以看成是与数据库中的表相映射的 Java 对象。
创建po即为创建于数据库中表对应的java类
数据库中的表:
在这里插入图片描述
对应的java对象
在这里插入图片描述
类中的属性也与数据库中属性对应
在这里插入图片描述
4.创建SqlMapConfig.xml 随便取 今天我们放在config下
创建configde 的source folder
在configde创建SqlMapConfig.xml的File
在这里插入图片描述

<?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="development">
 <environment id="development">
 <!-- jdbc事务管理控制,这里由mybatis管理 -->
 <transactionManager type="JDBC"/>
 <!-- 数据源的配置 -->
 <dataSource type="POOLED">
 <property name="driver" value="com.mysql.jdbc.Driver"/>
 <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
 <property name="username" value="root"/>
 <property name="password" value="root"/>
 </dataSource>
 </environment>
 </environments>
 <!-- 映射文件管理 -->
 <mappers>
 <mapper resource="com/xl/dao/User.xml"/>
 </mappers>
</configuration>

5.创建User.xml sql语句都定义在这文件下

<?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命名空间,取名为user -->
<mapper namespace="user">

  <!-- 1.根据id查询用户信息 
  		select:相当于statement对象
  		id:statement唯一标识,调用时使用 必需代表唯一
  		parameterType:输入映射类型,输入Java类型
  		resultType:输出映射类型 ,输出java类型 ,本例中输出的为User对象
  		#{}:相当于占位符
  -->
  
  <select id="FindUserById" parameterType="int" resultType="com.xl.po.User">
   SELECT * FROM  t_user where tid=#{value}
  </select>

</mapper>

6.在 SqlMapConfig.xml 文件中配置 User.xml
已在5中完成

7.测试

package test;

import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;


import com.xl.po.User;

public class UserTest {
	
	public static void main(String[] args) throws IOException {
		UserTest userTest=new UserTest();
		userTest.testFindUserById();
	}
	public void testFindUserById() throws IOException{
		
		//得到SqlMapConfig.xml 
		InputStream is=Resources.getResourceAsStream("SqlMapConfig.xml");
		//创建SqlSessionFactory
		SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
		//通过SqlSessionFactory创建SqlSession
		SqlSession sqlsession=sqlSessionFactory.openSession();
		//执行语句
		User user=sqlsession.selectOne("user.FindUserById", 1001);
		System.out.println(user);
		//释放资源
		sqlsession.close();
		
	}

}

8.创建log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 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

结果:
在这里插入图片描述

**示例2:根据用户名称模糊查询用户列表 **

重写第五步,第七步,其他照旧

创建User.xml sql语句

 <!-- 2.根据用户名称模糊查询用户列表  -->
  <select id="FindUserByName" parameterType="java.lang.String" resultType="com.xl.po.User">
   SELECT * FROM  t_user where uname like concat(concat('%',#{value}),'%');
  </select>

测试:

public void testFindUserByName() throws IOException{
		
		//得到SqlMapConfig.xml 
		InputStream is=Resources.getResourceAsStream("SqlMapConfig.xml");
		//创建SqlSessionFactory
		SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
		//通过SqlSessionFactory创建SqlSession
		SqlSession sqlsession=sqlSessionFactory.openSession();
		//执行语句
	    List<User> userlist=sqlsession.selectList("user.FindUserById", "二");
		System.out.println(userlist);
		//释放资源
		sqlsession.close();
		
	}

}

**示例3:添加用户 **

在User.xml添加

<!--3.添加用户  -->
  <insert id="insertUser" parameterType="com.luban.po.User">
  		INSERT INTO t_user(tid,uname,birthday,sex,address) 
  		VALUES(t_user_seq.nextval,#{uname},#{birthday},#{sex},#{address})
  </insert>

插入用户

public void testInsertUser() throws IOException{
		
		//得到SqlMapConfig.xml 
		InputStream is=Resources.getResourceAsStream("SqlMapConfig.xml");
		//创建SqlSessionFactory
		SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
		//通过SqlSessionFactory创建SqlSession
		SqlSession sqlsession=sqlSessionFactory.openSession();
		//创建User对象
		User user=new User();
		user.setUname("uname1");
		user.setSex('1');
		user.setAddress("山海");
		user.setBirthday(new Date());
		//执行语句
	   int i=sqlsession.insert("user.insertUser", user);
        //提交事务
	   sqlsession.commit();
	   if(i>0){
		   System.out.println("输出成功");
	   }
		//释放资源
		sqlsession.close();		
	}

小结

1,parameterType和resultType
parameterType指定输入参数的java类型,可以填写别名或java类的全限定名.
2,#{}和${}

#{}:相当于预处理中的占位符?。
#{}里面的参数表示接收java输入参数的名称。
#{}可以接受HashMap、简单类型、POJO类型的参数。
当接受简单类型的参数时,#{}里面可以是value,也可以是其他。
#{}可以防止SQL注入。

${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。
${}会引起SQL注入,所以要谨慎使用。
${}可以接受HashMap、简单类型、POJO类型的参数。
当接受简单类型的参数时,${}里面只能是value。

3,selecxtOne和selectList
selecxtOne:只能查询0或1条记录,大于1条记录的话,则报错
selectList:可以查询0或N条记录

在这里插入图片描述
在这里插入图片描述

二,mybatis开发dao

mybatis在项目中主要使用的地方就是开发dao(数据访问层 ),所以下面讲解一下一步mybatis开发dao的方法。有两种方式
1,原始dao开发方式(ibatis遗留下来的)
2.Mapper代理发发方式(推荐)

1,SqlSession使用范围

1、 SqlSessionFactoryBuilder
它的作用只是通过配置文件创建SqlSessionFactory,所以只要创建出SqlSessionFactory,它就可以销毁了。所以说,它的生命周期是在方法之内。

2、 SqlSessionFactory
它的作用是创建SqlSession的工厂,工厂一旦创建,除非应用停掉,不要销毁。
所以说它的生命周期是在应用范围内。这里可以通过单例模式来管理它。
在mybatis整合spring之后,最好的处理方式是把SqlSessionFactory交由spring来做单例管理。

3、 SqlSession
SqlSession是一个面向用户(程序员)的接口,它的默认实现是DefaultSqlSession。
Mybatis是通过SqlSession来操作数据库的。SqlSession中不仅包含要处理的SQL信息,还包括一些数据信息,所以说它是线程不安全的,因此它最佳的生命周期范围是在方法体之内。

2,原始dao开发方式

需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession
要注意SqlSession和SqlSessionFactory的生命周期。

Dao实现类代码

public class UserDaoImpl implements UserDao {

	//注入SqlSessionFactory
	private SqlSessionFactory sqlSessionFactory;
	//使用构造方法来初始化SqlSessionFactory
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory){
		this.sqlSessionFactory = sqlSessionFactory;
	}
	
	@Override
	public User findUserById(int id) {
		//通过工厂,在方法内部获取SqlSession,这样就可以避免线程不安全
		SqlSession sqlSession = sqlSessionFactory.openSession();
		//返回结果集
		return sqlSession.selectOne("test.findUserById", id);
	}

	@Override
	public List<User> findUsersByName(String username) {
		//通过工厂,在方法内部获取SqlSession,这样就可以避免线程不安全
		SqlSession sqlSession = sqlSessionFactory.openSession();
		return sqlSession.selectList("test.findUsersByName", username);
	}

	@Override
	public void insertUser(User user) {
		//通过工厂,在方法内部获取SqlSession,这样就可以避免线程不安全
		SqlSession sqlSession = sqlSessionFactory.openSession();
		sqlSession.insert("test.insertUser", user);
	}

}

编写测试代码
在这里插入图片描述
原始dao开发存在一些问题

1,存在一定量的模板代码。比如:通过SqlSessionFactory创建SqlSession;调用SqlSession的方法操作数据库;关闭Sqlsession。
2,存在一些硬编码。调用SqlSession的方法操作数据库时,需要指定statement的id,这里存在了硬编码
在这里插入图片描述

三,Mapper代理开发方式

Mapper代理的开发方式,程序员只需要编写mapper接口(相当于dao接口)即可。Mybatis会自动的为mapper接口生成动态代理实现类。
不过要实现mapper代理的开发方式,需要遵循一些开发规范。

1,开发规范

1、 mapper接口的全限定名要和mapper映射文件的namespace的值相同。
2、 mapper接口的方法名称要和mapper映射文件中的statement的id相同;
3、 mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
4、 mapper接口的方法参数如输入多个时接口中必需加入注解@Param,且mapper映射文件中不需要parameterType
5、 mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致;

通过规范式的开发mapper接口,可以解决原始dao开发当中存在的问题:
1、 模板代码已经去掉;
2、 剩下去不掉的操作数据库的代码,其实就是一行代码。这行代码中硬编码的部分,通过第一和第二个规范就可以解决。

即:

1. UserMapper.xml  名必需与接口名一至
2. SqlMapConfig.xml  与接口必需在同包下
3.-namespace命名空间 必需是接口的全限定名
3.statement id 必需与接口中的方法名一致
4.接口中的返回值必需与resultType类型一致
5.方法参数类型必需与parameterType类型一致
6.方法能数只能传一个参数
7.如果需要传递多个,加上注解,在mapper.xml文件中不需要定义parameterType

在这里插入图片描述
在这里插入图片描述

2,程序编写

1,
步骤中的1、2都在入门程序中进行了编写,此处不需要重新编写。
2,编写mapper映射文件
重新定义mapper映射文件UserMapper.xml(内容同Users.xml,除了namespace的值),放到新创建的目录mapper下
在这里插入图片描述
3,加载mapper映射文件

<!-- 加载mapper -->
<mappers>
	<mapper resource="mapper/UserMapper.xml"/>
</mappers>

4,编写mapper接口
在这里插入图片描述
5,编写测试代码

// 声明全局的SqlSessionFactory
private static SqlSessionFactory sqlSessionFactory ;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
	// 1、读取配置文件
	String sqlMapConfig = "SqlMapConfig.xml";
	InputStream is = Resources.getResourceAsStream(sqlMapConfig);
	// 2、根据配置文件创建SqlSessionFactory
	sqlSessionFactory= new SqlSessionFactoryBuilder().build(is);
}

@Test
public void testFindUserById() {
	// 创建SqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();
	// 通过SqlSession,获取mapper接口的动态代理对象
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	// 调用mapper对象的方法
	User user = userMapper.findUserById(1);
	System.out.println(user);
	// 关闭SqlSession
	sqlSession.close();
			
}

三,Mybatis全局配置文件

SqlMapConfig.xml是mybatis的全局配置文件,它的名称可以是任意命名的。
全部配置内容
SqlMapConfig.xml的配置内容和顺序如下(顺序不能乱)

Properties(属性)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境信息集合)
environment(单个环境信息)
transactionManager(事物)
dataSource(数据源)
mappers(映射器)

Properties
在这里插入图片描述
SqlMapConfig.xml使用properties标签后,如下所示:

<!-- 通过properties标签,读取java配置文件的内容 -->
<properties resource="db.properties" />

<!-- 配置mybatis的环境信息 -->
<environments default="development">
	<environment id="development">
		<!-- 配置JDBC事务控制,由mybatis进行管理 -->
		<transactionManager type="JDBC"></transactionManager>
		<!-- 配置数据源,采用dbcp连接池 -->
		<dataSource type="POOLED">
			<property name="driver" value="${db.driver}"/>
			<property name="url" value="${db.url}"/>
			<property name="username" value="${db.username}"/>
			<property name="password" value="${db.password}"/>
		</dataSource>
	</environment>
</environments>

注:
mybatis将按照下面的顺序加载属性:
使用${},可以引用已经加载的java配置文件中的信息。
Properties标签体内定义的属性首先被读取
Properties引用的属性会被读取,如果发现上面已经有同名的属性了,那后面会覆盖前面的值
parameterType接收的值会最后被读取,如果发现上面已经有同名的属性了,那后面会覆盖前面的值

所以说,mybatis读取属性的顺序由高到低分别是:parameterType接收的属性值、properties引用的属性、properties标签内定义的属性。

Settings
typeAliases

SqlMapConfig.xml配置信息如下:

<!-- 定义别名 -->
	<typeAliases>
		<!-- 单个定义别名 -->
		<typeAlias type="com.mybatis.po.User" alias="user"/>
		
		<!-- 批量定义别名(推荐) -->
		<!-- [name]:指定批量定义别名的类包,别名为类名(首字母大小写都可) -->
		<package name="com.mybatis.po"/>
	</typeAliases>

mappers

使用相对于类路径的资源
如:

<mapper resource="sqlmap/User.xml" />

使用完全限定路径
如:

<mapper url="file:///D:\workspace_spingmvc\mybatis_01\config\sqlmap\User.xml" />

使用mapper接口的全限定名
如:

<mapper class="com.mybatis.mapper.UserMapper"/>

注意:此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下;

注册指定包下的所有映射文件
如:

<package name="com.mybatis.mapper"/>

四,Mybatis映射文件

1,输入映射

1.1 ParameterType

指定输入参数的java类型,可以使用别名或者类的全限定名。它可以接收简单类型、POJO、HashMap

传递简单类型
参考入门需求:根据用户ID查询用户信息:
在这里插入图片描述
传递POJO对象
参考入门需求:添加用户:
在这里插入图片描述
传递POJO包装对象
开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
例:
1,需求:
综合查询用户信息,需要传入查询条件复杂,比如(用户信息、订单信息、商品信息)。
2,定义包装对象:
一般User.java类要和数据表表字段一致,最好不要在这里面添加其他字段,如果使用mybatis的逆向工程时,会根据表结构,生成po类,如果在po类中扩展字段,此时会被覆盖掉。
所以针对要扩展的po类,我们需要创建一个扩展类,来继承它。

MyBatis的逆向工程指利用MyBatis Generator(MBG),可以快速的根据表生成对应的映射文件,接口,以及bean类。
在这里插入图片描述
3,编写Mapper接口

//通过包装类来进行复杂的用户信息综合查询
public List<UserExt> findUserList(UserQueryVO userQueryVO);

4,编写mapper映射文件

<!-- 通过包装类来进行复杂的用户信息综合查询 -->
<select id="findUserList" parameterType="userQueryVO" resultType="userExt">
		SELECT * FROM USER WHERE sex=#{userExt.sex} AND username LIKE '%${userExt.username}%'
</select>

:入参的类型变为UserQueryVO、结果集的类型变为UserExt,#{}里面的参数变为UserQueryVO对象中的userExt属性的sex和username子属性。

5,编写测试代码

传递HashMap
同传递POJO对象一样,map的key相当于pojo的属性
1,映射文件

<!-- 传递hashmap综合查询用户信息 -->
	<select id="findUserByHashmap" parameterType="hashmap" resultType="user">
	   select * from user where id=#{id} and username like '%${username}%'
	</select>

2,测试代码

Public void testFindUserByHashmap()throws Exception{
		//获取session
		SqlSession session = sqlSessionFactory.openSession();
		//获限mapper接口实例
		UserMapper userMapper = session.getMapper(UserMapper.class);
		//构造查询条件Hashmap对象
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("id", 1);
		map.put("username", "管理员");
		
		//传递Hashmap对象查询用户列表
		List<User>list = userMapper.findUserByHashmap(map);
		//关闭session
		session.close();
	}

异常测试:
传递的map中的key和sql中解析的key不一致。
测试结果没有报错,只是通过key获取值为空。

2,输出映射

2.1 resultType

1, 使用方法

使用resultType进行结果映射时,查询的列名和映射的pojo属性名完全一致,该列才能映射成功。
如果查询的列名和映射的pojo属性名全部不一致,则不会创建pojo对象;
如果查询的列名和映射的pojo属性名有一个一致,就会创建pojo对象。

2,输出简单类型
当输出结果只有一列时,可以使用ResultType指定简单类型作为输出结果类型。

例:
1,需求
查询用户总数

2,Mapper映射文件

<!-- 查询用户信息总数-->
<select id="findUsersCount" parameterType="UserVo"
		resultType="int">
		SELECT count(1) FROM USER WHERE sex = #{userExt.sex} AND username	LIKE '%${userExt.username}%'
</select>

3,Mapper接口

//综合查询用户信息总数。学习:resultType输出简单类型
public int findUsersCount(UserVo vo);

4,测试代码

3,输出POJO单个对象和列表
注意:输出单个pojo对象和pojo列表(盛放pojo对象)时,mapper映射文件中的resultType的类型是一样的,mapper接口的方法返回值不同。
1,Mapper映射文件
Mapper映射文件是同一个

<select id="findUsersByName" parameterType="java.lang.String" resultType="com.mybatis.po.User">
		SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>

2,Mapper接口
下面看下mapper接口的不同之处
1、 输出单个pojo对象

//根据用户名称来模糊查询用户信息
	public User findUsersByName(String username);

2、 输出pojo列表

//根据用户名称来模糊查询用户信息列表
	public List<User> findUsersByName(String username);

总结:同样的mapper映射文件,返回单个对象和对象列表时,mapper接口在生成动态代理的时候,会根据返回值的类型,决定调用selectOne方法还是selectList方法。

2.2 resultMap

resultMap可以进行高级结果映射(一对一、一对多映射,后面课程讲解)。

1,使用方法

如果查询出来的列名和属性名不一致,通过定义一个resultMap将列名和pojo属性名之间作一个映射关系。
定义resultMap
使用resultMap作为statement的输出映射类型。

2, 需求
把下面SQL的输出结果集进行映射

SELECT id id_,username username_,sex sex_ FROM USER WHERE id = 1

3,Mapper映射文件
定义resultMap:

<!-- 定义resultMap -->
<!-- 
	[id]:定义resultMap的唯一标识
	[type]:定义该resultMap最终映射的pojo对象
	[id标签]:映射结果集的唯一标识列,如果是多个字段联合唯一,则定义多个id标签
	[result标签]:映射结果集的普通列
	[column]:SQL查询的列名,如果列有别名,则该处填写别名
	[property]:pojo对象的属性名
-->
<resultMap type="user" id="userResultMap">
	<id column="id_" property="id"/>
	<result column="username_" property="username"/>
	<result column="sex_" property="sex"/>
</resultMap>

定义statement:

<!-- 根据ID查询用户信息 -->
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
SELECT id id_,username username_,sex sex_ FROM USER WHERE id = #{id}
</select>

4,Mapper接口定义

//根据ID查询用户信息
public User findUserByIdResultMap(int id);

定义Statement使用resultMap映射结果集时,Mapper接口定义方法的返回值类型为mapper映射文件中resultMap的type类型。

5, 测试代码

@Test
public void findUserByIdResultMapTest() {
	// 创建SqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();
	// 通过SqlSession,获取mapper接口的动态代理对象
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

	// 调用mapper对象的方法
	User user = userMapper.findUserByIdResultMap(1);

	System.out.println(user);
	// 关闭SqlSession
	sqlSession.close();
}

3,动态SQL

通过Mybatis提供的各种动态标签实现动态拼接sql,使得mapper映射文件在编写SQL时更加灵活,方便。常用动态SQL标签有:if、where、foreach;

3.1 If 和 where

If标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上。

注意:用if进行判断是否为空时,不仅要判断null,也要判断空字符串‘’;

Where标签:会去掉条件中的第一个and符号。

1, 需求
用户信息综合查询列表和用户信息综合查询总数这两个statement的定义使用动态SQL
2,映射文件

<!-- 综合查询用户信息,需要传入查询条件复杂,比如(用户信息、订单信息、商品信息) -->
<select id="findUsersByQueryVO" parameterType="com.mybatis.po.QueryUserVO"
		resultType="User">
		SELECT * FROM USER
	<where>
		<if test="userExt != null">
			<if test="userExt.sex != null and userExt.sex != ''">
				AND sex = #{userExt.sex}
			</if>
			<if test="userExt.username != null and userExt.username != ''">
				AND username LIKE '%${userExt.username}%'
			</if>
		</if>
	</where>
</select>
	
<!-- 综合查询用户信息总数,需要传入查询条件复杂,比如(用户信息、订单信息、商品信息) -->
<select id="findUsersCount" parameterType="QueryUserVO"
		resultType="int">
	SELECT count(1) FROM USER 
	<where>
		<if test="userExt != null">
			<if test="userExt.sex != null and userExt.sex != ''">
				AND sex = #{userExt.sex}
			</if>
			<if test="userExt.username != null and userExt.username != ''">
				AND username LIKE '%${userExt.username}%'
			</if>
		</if>
	</where>
</select>

3, Mapper接口

//通过包装类来进行复杂的用户信息综合查询
public List<UserExt> findUserList(UserQueryVO userQueryVO);
//综合查询用户总数
public int findUsersCount(UserQueryVO userQueryVO);

4,测试代码
不传用户名:
在这里插入图片描述
输出的SQL如下(也不包含用户名):
在这里插入图片描述
通过测试可以得知,打印出的SQL语句确实会随着条件的满足情况而不一样。

3.1 If Set改造

1,映射文件

<!-- 修改 -->
  <update id="updateUserSet" parameterType="user">
  		update t_user 
	<set>
		<if test="uname!=null">
			uname =#{uname},
		</if>
		<if test="birthday!=null">
			birthday =#{birthday},
		</if>
		<if test="sex!=null and sex!=0">
			sex =#{sex},
		</if>
		<if test="address!=null">
			address =#{address},
		</if>
	</set>
	where tid=#{tid}
  </update>

2,Mapper接口

//修改
	public int updateUserSet(User user);

3,测试代码

@Test
public void updateUserSet() {
	SqlSession sqlSession = sqlSessionFactory.openSession();
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	User user = new User();
	user.setSex('1');
	user.setUname("小3");
	user.setAddress(" 刚修改");
	user.setTid(5);
	userMapper.updateUserSet(user);
	sqlSession.close();
}

3.3 SQL片段

Mybatis提供了SQL片段的功能,可以提高SQL的可重用性。

1, 定义SQL片段
使用sql标签来定义一个SQL片段:

<!-- 定义SQL片段 -->
<!-- 
	[sql标签]:定义一个SQL片段
	[id]:SQL片段的唯一标识
	建议:
		1、SQL片段中的内容最好是以单表来定义
		2、如果是查询字段,则不要写上SELECT
		3、如果是条件语句,则不要写上WHERE
 -->
<sql id="select_user_where">
	<if test="userExt != null">
		<if test="userExt.sex != null and userExt.sex != ''">
			AND sex = #{userExt.sex}
		</if>
		<if test="userExt.username != null and userExt.username != ''">
			AND username LIKE '%${userExt.username}%'
		</if>
	</if>
</sql>

2,引用SQL片段
使用 来引用SQL片段:

<!-- 根据用户id来查询用户信息(使用SQL片段) -->
<!-- 
	[include标签]:引用已经定义好的SQL片段
	[refid]:引用的SQL片段id
-->
<select id="findUserList" parameterType="userQueryVO" resultType="userExt">

	SELECT * FROM USER 
<where>
		<include refid="select_user_where"/>
	</where>
</select>
<!-- 综合查询用户信息总数,需要传入查询条件复杂,比如(用户信息、订单信息、商品信息) -->
<select id="findUsersCount" parameterType="QueryUserVO"
		resultType="int">
	SELECT count(1) FROM USER 
	<where>
		<include refid="select_user_where"/>
	</where>
</select>

3.4 Foreach

向sql传递数组或List时,mybatis使用foreach解析数组里的参数并拼接到SQL中。

传递pojo对象中的List集合
1,需求
在用户查询列表和查询总数的statement中增加多个id输入查询。
2,SQL
SELECT * FROM user WHERE id IN (1,10,16)
3,定义pojo中的List属性
在这里插入图片描述
4,映射文件

<!-- [foreach标签]:表示一个foreach循环 -->
<!-- [collection]:集合参数的名称,如果是直接传入集合参数,则该处的参数名称只能填写[list]。 -->
<!-- [item]:每次遍历出来的对象 -->
<!-- [open]:开始遍历时拼接的串 -->
<!-- [close]:结束遍历时拼接的串 -->
<!-- [separator]:遍历出的每个对象之间需要拼接的字符 -->
<if test="idList != null and idList.size > 0">
<foreach collection="idList" item="id" open="AND id IN (" close=")" separator=",">
		#{id}
</foreach>
</if>

5,Mapper接口

//根据用户ID的集合查询用户列表(学习foreach标签之通过POJO对象传ID集合)
public List<UserExt> findUserList(UserQueryVO vo);

6,测试代码

@Test
public void testFindUserList() {
	// 创建SqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();
	// 通过SqlSession,获取mapper接口的动态代理对象
	UserMapper mapper = sqlSession.getMapper(UserMapper.class);

	// 构造QueryUserVO对象
	QueryUserVO vo = new QueryUserVO();
	// UserExt ext = new UserExt();
	// ext.setUsername("小明");
	// ext.setSex("1");
	// vo.setUserExt(ext);

	// 创建用户ID集合,然后设置到QueryUserVO对象中
	List<Integer> idList = new ArrayList<Integer>();
	idList.add(1);
	idList.add(10);
	idList.add(16);
	vo.setIdList(idList);

	// 调用mapper代理对象的方法
	List<UserExt> list = mapper.findUserList(vo);
	System.out.println(list);
	// 关闭SqlSession
	sqlSession.close();
}

四,关联查询映射

1,分析数据模型

1,思路
1、 每张表记录的数据内容
分模块对每张表记录的内容进行熟悉,相当于你学习系统需求(功能)的过程。
2、 每张表重要的字段
主键、外键、非空字段
3、 数据库级别表与表的关系
外键关系
4、 表与表之间的业务关系
在分析表与表之间的业务关系时一定要建立 在某个业务意义基础上去分析。

2,图形分析
在这里插入图片描述
3,数据库表之间有外键关系的业务关系
user和orders:
user---->orders:一个用户可以创建多个订单,一对多
orders—>user:一个订单只由一个用户创建,一对一

orders和orderdetail:
orders---->orderdetail:一个订单可以包括 多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系
orderdetail–> orders:一个订单明细只能包括在一个订单中,一对一

orderdetail和itesm:
orderdetail—>itesms:一个订单明细只对应一个商品信息,一对一
items–> orderdetail:一个商品可以包括在多个订单明细 ,一对多

4,数据库表之间没有外键关系的业务关系
Orders和items:
这两张表没有直接的外键关系,通过业务及数据库的间接关系分析出它们是多对多的关系。
Orders–> orderdetail –>items:一个订单可以有多个订单明细,一个订单明细对应一个商品,所以一个订单对应多个商品
Items–>orderdetail–>orders:一个商品可以对应多个订单明细,一个订单明细对应一个订单,所以一个商品对应多个订单

User和items:
这两张表没有直接的外键关系,通过业务及数据库的间接关系分析出它们是多对多的关系。
User–>orders–>orderdetail–>items:一个用户有多个订单,一个订单有多个订单明细、一个订单明细对应一个商品,所以一个用户对应多个商品
Items–>orderdetail–>orders–>user:一个商品对应多个订单明细,一个订单明细对应一个订单,一个订单对应一个用户,所以一个商品对应多个用户

2,一对一查询

1,需求:
查询订单信息,关联查询创建订单的用户信息
2,SQL语句
确定查询的主表:订单表
确定查询的关联表:用户表

SELECT
	o.id,
	o.order_Number,
	o.createtime,
	o.describer,
	o.user_id
	userId,
	u.uname,
	u.address
FROM orders o,t_user u 
WHERE o.user_id=u.tid;

3,resultType
复杂查询时,单表对应的po类已不能满足输出结果集的映射。
所以要根据需求建立一个扩展类来作为resultType的类型。

1,创建po类

//通过此类映射订单和用户查询的结果,让此类继承包括 字段较多的pojo类
public class OrdersExt extends Orders{
	//添加用户属性
	/*USER.username,  USER.address */
	private String username;
	private String address;
}

2,编写mapper接口
创建OrdersMapper接口类,在类中添加以下内容:

//	进行订单信息查询,包括用户的名称和地址信息
public List<OrdersExt> findOrdersUser();

3,编写映射文件

<mapper namespace="com.mybatis.mapper.OrdersMapper">

	<!-- 定义查询订单表列名的SQL片段 -->
	<sql id="select_orders">
		Orders.id,
		Orders.user_id,
		orders.number,
		orders.createtime,
		orders.note
	</sql>
	<!-- 定义查询用户表列名的SQL片段 -->
	<sql id="select_user">
		user.username,
		user.address
	</sql>
	<!-- 进行订单信息查询,包括用户的名称和地址信息 -->
	<select id="findOrdersUser" resultType="OrdersExt">
		Select
		<include refid="select_orders" />
		<include refid="select_user"></include>
		from orders,user
		where orders.user_id = user.id
	</select>
</mapper>

4,加载映射文件

<!-- 批量加载mapper文件,需要mapper接口文件和mapper映射文件名称相同且在同一个包下 -->
<package name="com.mybatis.mapper"/>

5, 编写测试代码

@Test
public void testFindOrdersUser() {
	// 创建sqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();
	// 通过SqlSession构造usermapper的代理对象
	OrdersMapper orders qlSession.getMapper(OrdersMapper.class);
	// 调用usermapper的方法
	// 释放SqlSession
	sqlSession.close();
}

4,resultMap
1,修改po类
在Orders类中,添加User对象

public class Orders {
    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

    private String note;
    
    //用户信息
    private User user;

2,编写mapper接口

//	进行订单信息查询,包括用户的名称和地址信息(resultMap)
public List<OrdersExt> findOrdersUserRstMap();

3,编写映射文件

<!-- 进行订单信息查询,包括用户的名称和地址信息 (ResultMap) -->
	<select id="findOrdersUserRstMap" resultMap="OrdersUserRstMap">
		Select
		<include refid="select_orders" />
		,
		<include refid="select_user"></include>
		from orders,user
		where orders.user_id = user.id
	</select>

	<!-- 定义orderUserResultMap -->
	<resultMap type=" com.mybatis.po.Orders" id="OrdersUserRstMap">
		<id column="id" property="id" />
		<result column="user_id" property="userId" />
		<result column="number" property="number" />
		<result column="createtime" property="createtime" />
		<result column="note" property="note" />
		<!-- 映射一对一关联关系的用户对象-->
		<!-- 
			property:指定关联对象要映射到Orders的哪个属性上 
			javaType:指定关联对象所要映射的java类型
		  -->
		<!-- id标签:指定关联对象结果集的唯一标识,很重要,不写不会报错,但是会影响性能 -->
		<association property="user" javaType="com.mybatis.po.User">
			<id column="user_id" property="id" />
			<result column="username" property="username" />
			<result column="address" property="address" />
		</association>
	</resultMap>

4,编写测试代码

@Test
public void testFindOrdersUserRstMap() {
	// 创建sqlSession
	SqlSession sqlSession = sqlSessionFactory.openSession();

	// 通过SqlSession构造usermapper的代理对象
	OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
	// 调用usermapper的方法
	List<Orders> list = ordersMapper.findOrdersUserRstMap();
		
	//此处我们采用debug模式来跟踪代码,然后验证结果集是否正确
	System.out.println(list);
	// 释放SqlSession
	sqlSession.close();
}

5,一对一小结
实现一对一查询:
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
如果没有查询结果的特殊要求建议使用resultType。

resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的对象属性中。

resultMap可以实现延迟加载,resultType无法实现延迟加载。

3,一对多查询

一对多查询和一对一查询的配置基本类似。只是如果使用resultMap的话,映射一对多关联关系要使用collection标签。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值