一、 MyBatis介绍
序号 |
Mybatis |
hibernate |
iBatis SSI 2002年诞生 Cliton begin |
2001年 Given King |
|
2010年5月由apache投奔google |
Jboss,apache |
|
基于SQL 面向结果集 |
基于面向对象 HQL |
|
效率高 |
效率低 |
|
SqlSessionFactory |
SessionFactory |
|
SqlSession |
Session |
|
sqlMapConfig.xml |
Hibernate.cfg.xml |
|
userMapper.xml |
映射文件 user.hbm.xml |
Hibernate面向对象,它使用HQL,可以无需写SQL语句。全自动ORM。
Mybatis面向对象,它使用SQL语句,很依赖于SQL语句。半自动ORM。
mybatis架构:
1、 mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、 mybatis底层自定义了Executor接口操作数据库,Executor接口有两个实现,一个是基本实现、一个是缓存实现。
5、 Mapped Statement也是mybatis一个底层对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
二、 体验Mybatis
1. 创建一个java工程
使用eclipse创建java工程,jdk使用1.6。
2. 导入jar
加入mybatis核心包、依赖包、数据驱动包。
3. log4j.properties
在classpath下创建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
mybatis默认使用log4j作为输出日志信息。
4. SqlMapConfig.xml
在classpath下创建SqlMapConfig.xml,如下:
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEconfiguration PUBLIC"-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--<properties resource=""></properties> --> <environmentsdefault="development"> <environmentid="development"> <transactionManagertype="JDBC"/> <dataSourcetype="POOLED"> <propertyname="driver"value="com.mysql.jdbc.Driver"/> <propertyname="url"value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/> <propertyname="username"value="root"/> <propertyname="password"value="mysql"/> </dataSource> </environment> </environments> </configuration>
SqlMapConfig.xml是mybatis核心配置文件,上边文件的配置内容为数据源、事务管理。
5. po类
Po类作为mybatis进行sql映射使用,po类通常与数据库表对应,User.java如下:
publicclass User { private int id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 出生日期 private String address;// 地址 private String detail;// 详细信息 private Float score;// 成绩 get/set……
6.sql映射文件
在classpath下的sqlmap目录下创建sql映射文件User.xml:
<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEmapper PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mappernamespace="test"> <!--根据id获取用户信息 --> <selectid="selectUserById" parameterType="int"resultType="cn.itcast.mybatis.po.User"> select * from user where id = #{id} </select> <!--获取用户列表 --> <selectid="selectUserList" resultType="cn.itcast.mybatis.po.User"> select * from user </select> <!--添加用戶 --> <insertid="insertUser" parameterType="cn.itcast.mybatis.po.User"> insert into user(username,birthday,sex,address,detail,score) values(#{username},#{birthday},#{sex},#{address},#{detail},#{score}) </insert> <!--更新用戶 --> <updateid="updateUser" parameterType="cn.itcast.mybatis.po.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address},detail=#{detail},score=#{score} where id=#{id} </update> <!--刪除用戶 --> <deleteid="deleteUser" parameterType="cn.itcast.mybatis.po.User"> delete from user where id=#{id} </delete> </mapper>
namespace :命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用。
parameterType:定义输入到sql中的映射类型,#{id}表示使用preparedstatement设置占位符号并将输入变量id传到sql。id是实体类的属性名
resultType:定义结果映射类型。
7.将User.xml添加在SqlMapConfig.xml
在SqlMapConfig.xml中添加mappers如下:
<mappers> <mapperresource="sqlmap/user.xml"/> </mappers>
这里即告诉mybatis Sql映射文件在哪里。
8.程序编写
查询
/** * 第一个mybatis程序 * * @authorThinkpad * */ publicclass Mybatis_select { publicstaticvoid main(String[] args) throws IOException { //mybatis配置文件 String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //使用SqlSessionFactoryBuilder创建sessionFactory SqlSessionFactory sqlSessionFactory = newSqlSessionFactoryBuilder() .build(inputStream); //通过session工厂获取一个Sqlsession,sqlsession中包括了对数据库操作的sql方法 SqlSession session = sqlSessionFactory.openSession(); try { //通过sqlsession调用selectOne方法获取一条结果集 //参数1:指定定义的statement的id,参数2:指定向statement中传递的参数 User user = session.selectOne("test.selectUserById", 1); System.out.println(user); } finally{ session.close(); } } }
添加
public class Mybatis_insert { publicstaticvoid main(String[] args) throws IOException { //mybatis配置文件 String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //使用SqlSessionFactoryBuilder创建sessionFactory SqlSessionFactory sqlSessionFactory = newSqlSessionFactoryBuilder() .build(inputStream); //通过session工厂获取一个Sqlsession,sqlsession中包括了对数据库操作的sql方法 SqlSession session = sqlSessionFactory.openSession(); try { User user = newUser(); user.setUsername("张三"); user.setBirthday(new Date()); user.setSex("1"); user.setAddress("北京市"); user.setDetail("好同志"); user.setScore(99.8f); session.insert("test.insertUser", user); session.commit(); } finally{ session.close(); } } }
主键返回
通过修改sql映射文件,可以将mysql自增主键返回:
<insert id="insertUser"parameterType="cn.itcast.mybatis.po.User"> <!-- selectKey将主键返回,需要再返回 --> <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>
添加selectKey实现将主键返回
keyProperty:返回的主键存储在pojo中的哪个属性
order:selectKey的执行顺序,是相对与insert语句来说,由于mysql的自增原理执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after
resultType:返回的主键是什么类型
LAST_INSERT_ID():是mysql的函数
Oracle可采用序列完成:
首先自定义一个序列且于生成主键,selectKey使用如下:
<selectKey resultType="java.lang.Integer" order="BEFORE"
keyProperty="id">
SELECT 自定义序列.NEXTVAL FROM DUAL
</selectKey>
注意这里使用的order是“BEFORE”
删除
public class Mybatis_delete { publicstaticvoid main(String[] args) throws IOException { //mybatis配置文件 String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //使用SqlSessionFactoryBuilder创建sessionFactory SqlSessionFactory sqlSessionFactory = newSqlSessionFactoryBuilder() .build(inputStream); //通过session工厂获取一个Sqlsession,sqlsession中包括了对数据库操作的sql方法 SqlSession session = sqlSessionFactory.openSession(); try { session.delete("test.deleteUser", 4); session.commit(); } finally{ session.close(); } } }
修改
public class Mybatis_update { public static void main(String[] args) throws IOException { //mybatis配置文件 String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //使用SqlSessionFactoryBuilder创建sessionFactory SqlSessionFactory sqlSessionFactory = newSqlSessionFactoryBuilder() .build(inputStream); //通过session工厂获取一个Sqlsession,sqlsession中包括了对数据库操作的sql方法 SqlSession session = sqlSessionFactory.openSession(); try { User user = newUser(); user.setId(4); user.setUsername("李四"); user.setBirthday(new Date()); user.setSex("1"); user.setAddress("北京市"); user.setDetail("好同志"); user.setScore(99.8f); session.update("test.updateUser", user); session.commit(); } finally{ session.close(); } } }
三、Namespace的作用(重要)
命名空间除了对sql进行隔离,mybatis中对命名空间有特殊的作用,用于定义mapper接口地址。
问题:
没有使用接口编程,java是面向接口编程语言,对数据库的操作应该定义一些操作接口,如:用户添加、用户删除、用户查询等,调用dao接口完成数据库操作。
解决:
public interface UserDao { public User getUserById(int id) throws Exception; public void insertUser(User user) throws Exception; }
public class UserDaoImpl implements UserDao { public UserDaoImpl(SqlSessionFactory sqlSessionFactory){ this.setSqlSessionFactory(sqlSessionFactory); } private SqlSessionFactory sqlSessionFactory; @Override public User getUserById(int id) throws Exception { SqlSession session = sqlSessionFactory.openSession(); User user = null; try { //通过sqlsession调用selectOne方法获取一条结果集 //参数1:指定定义的statement的id,参数2:指定向statement中传递的参数 user = session.selectOne("selectUserById", 1); System.out.println(user); //获取List List<User> list = session.selectList("selectUserList"); System.out.println(list); } finally{ session.close(); } return user; } @Override publicvoid insertUser(User user) throws Exception { SqlSession session = sqlSessionFactory.openSession(); try { session.insert("insertUser", user); session.commit(); } finally{ session.close(); } } public SqlSessionFactory getSqlSessionFactory() { return sqlSessionFactory; } publicvoid setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } }
问题:
第一个例子中,在访问sql映射文件中定义的sql时需要调用sqlSession的selectOne方法,并将sql的位置(命名空间+id)和参数传递到selectOne方法中,且第一个参数是一个长长的字符串,第二个参数是一个object对象,这对于程序编写有很大的不方便,很多问题无法在编译阶段发现。
虽然上边对提出的面向接口编程问题进行解决,但是dao实现方法中仍然是调用sqlSession的selectOne方法,重复代码多。
改为mapper 接口实现:
第一步:定义mapper.xml
Mapper.xml文件不变还用原来的。
第二步:定义mapper 接口
/** * 用户管理mapper * @authorThinkpad * */ public interface UserMapper { public User selectUserById(int id) throws Exception; public List<User> selectUserList() throws Exception; public void insertUser(User user) throws Exception; public void updateUser(User user) throws Exception; public voiddeleteUser(int id) throws Exception; }
接口定义有如下特点:
1、 Mapper接口方法名和mapper.xml中定义的每个sql的id相同
2、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
3、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
第三步:修改namespace
Mapper.xml映射文件中的namepace改为如下:
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
修改后namespace即是mapper接口的地址。
第四步:通过mapper接口调用statement
public class UserMapperTest extends TestCase { private SqlSessionFactory sqlSessionFactory; protected void setUp() throws Exception { //mybatis配置文件 String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //使用SqlSessionFactoryBuilder创建sessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } public void testSelectUserById() throws Exception { //获取session SqlSession session = sqlSessionFactory.openSession(); //获取mapper接口实例 UserMapper userMapper = session.getMapper(UserMapper.class); //通过mapper接口调用statement User user = userMapper.selectUserById(1); System.out.println(user); //关闭session session.close(); } public void testSelectUserList() throws Exception { //获取session SqlSession session = sqlSessionFactory.openSession(); //获取mapper接口实例 UserMapper userMapper = session.getMapper(UserMapper.class); //通过mapper接口调用statement List<User>list = userMapper.selectUserList(); System.out.println(list); //关闭session session.close(); } public void testInsertUser() throws Exception { //获取session SqlSession session = sqlSessionFactory.openSession(); //获限mapper接口实例 UserMapper userMapper = session.getMapper(UserMapper.class); //要添加的数据 User user = newUser(); user.setUsername("张三"); user.setBirthday(new Date()); user.setSex("1"); user.setAddress("北京市"); user.setDetail("好同志"); user.setScore(99.8f); //通过mapper接口添加用户 userMapper.insertUser(user); //提交 session.commit(); //关闭session session.close(); } public void testUpdateUser() throws Exception { //获取session SqlSession session = sqlSessionFactory.openSession(); //获限mapper接口实例 UserMapper userMapper = session.getMapper(UserMapper.class); //要更新的数据 User user = newUser(); user.setId(7); user.setUsername("李四"); user.setBirthday(new Date()); user.setSex("1"); user.setAddress("北京市"); user.setDetail("好同志"); user.setScore(99.8f); //通过mapper接口调用statement userMapper.updateUser(user); //提交 session.commit(); //关闭session session.close(); } public void testDeleteUser() throws Exception { //获取session SqlSession session = sqlSessionFactory.openSession(); //获限mapper接口实例 UserMapper userMapper = session.getMapper(UserMapper.class); //通过mapper接口删除用户 userMapper.deleteUser(6); //提交 session.commit(); //关闭session session.close(); } }
session.getMapper(UserMapper.class)生成一个代理对象作为UserMapper的接口实现对象。
总结:
使用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接口两种文件。
四、SqlMapConfig.xml
配置内容
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
properties(属性)
SqlMapConfig.xml可以引用java属性文件中的配置信息如下:
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=mysql
SqlMapConfig.xml引用如下:
<properties resource="db.properties"/> <environments default="development"> <environment id="development"> <transaction Managertype="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>
typeAliases(类型别名)
mybatis支持别名:
别名 |
映射的类型 |
_byte |
byte |
_long |
long |
_short |
short |
_int |
int |
_integer |
int |
_double |
double |
_float |
float |
_boolean |
boolean |
string |
String |
byte |
Byte |
long |
Long |
short |
Short |
int |
Integer |
integer |
Integer |
double |
Double |
float |
Float |
boolean |
Boolean |
date |
Date |
decimal |
BigDecimal |
bigdecimal |
BigDecimal |
自定义别名:
在SqlMapConfig.xml中配置:
<typeAliases> <!--单个别名定义 --> <typeAlias alias="user" type="cn.itcast.mybatis.po.User"/> <!--批量别名定义,扫描整个包下的类 别名默认为类名首字母小写--> <package name="cn.itcast.mybatis.po"/> </typeAliases>
typeHandlers(类型处理器)
类型处理器在将java类型和sql映射文件进行映射时使用,如下:
<select id="selectUserById" parameterType="int" resultType="user"> select * from user where id = #{id} </select>
parameterType:指定输入数据类型为int,即向statement设置值
resultType:指定输出数据类型为自定义User,即将resultset转为java对象
mybatis自带的类型处理器基本上满足日常需求,不需要单独定义。
mybatis支持类型处理器:
类型处理器 |
Java类型 |
JDBC类型 |
BooleanTypeHandler |
Boolean,boolean |
任何兼容的布尔值 |
ByteTypeHandler |
Byte,byte |
任何兼容的数字或字节类型 |
ShortTypeHandler |
Short,short |
任何兼容的数字或短整型 |
IntegerTypeHandler |
Integer,int |
任何兼容的数字和整型 |
LongTypeHandler |
Long,long |
任何兼容的数字或长整型 |
FloatTypeHandler |
Float,float |
任何兼容的数字或单精度浮点型 |
DoubleTypeHandler |
Double,double |
任何兼容的数字或双精度浮点型 |
BigDecimalTypeHandler |
BigDecimal |
任何兼容的数字或十进制小数类型 |
StringTypeHandler |
String |
CHAR和VARCHAR类型 |
ClobTypeHandler |
String |
CLOB和LONGVARCHAR类型 |
NStringTypeHandler |
String |
NVARCHAR和NCHAR类型 |
NClobTypeHandler |
String |
NCLOB类型 |
ByteArrayTypeHandler |
byte[] |
任何兼容的字节流类型 |
BlobTypeHandler |
byte[] |
BLOB和LONGVARBINARY类型 |
DateTypeHandler |
Date(java.util) |
TIMESTAMP类型 |
DateOnlyTypeHandler |
Date(java.util) |
DATE类型 |
TimeOnlyTypeHandler |
Date(java.util) |
TIME类型 |
SqlTimestampTypeHandler |
Timestamp(java.sql) |
TIMESTAMP类型 |
SqlDateTypeHandler |
Date(java.sql) |
DATE类型 |
SqlTimeTypeHandler |
Time(java.sql) |
TIME类型 |
ObjectTypeHandler |
任意 |
其他或未指定类型 |
EnumTypeHandler |
Enumeration类型 |
VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。 |
mappers(映射器)
Mapper配置的几种方法:
<mapper resource=" " />
使用相对于类路径的资源
如:<mapper resource="sqlmap/user.xml" />
<mapper url=" " />
使用完全限定路径
如:<mapper url="file:///D:workspace_spingmvcmybatis_01configsqlmapuser.xml" />
<mapper class=" " />
使用mapper接口类路径
如:<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<package name=""/>
注册指定包下的所有mapper接口
如:<package name="cn.itcast.mybatis.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
五、 Mapper.xml
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
#{}与${}
#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?。
<!--根据id查询用户信息 --> <select id="selectUserById" parameterType="int" resultType="user"> select * from user where id = #{id} </select>
使用占位符#{}可以有效防止sql注入,在使用时不需要关心参数值的类型,mybatis会根据参数值的类型调用不同的statement设置参数值的方法。可以想象为:如果参数值是一个字符串则自动映射生成的sql中参数值两边自动有单引号,如果参数值是一个数字型则自动映射生成的sql中参数值两边没有单引号。
注意:当传递单个值时#{}中的参数名称通常和mapper接口的形参名称相同,也可以设置成任意值。
${}和#{}不同,${}是将参数值不加修饰的拼在sql中,相当中用jdbc的statement拼接sql,使用${}不能防止sql注入,但是有时用${}会非常方便,如下的例子:
<!--根据名称模糊查询用户信息 --> <select id="selectUserByName" parameterType="string" resultType="user"> select * from user where username like '%${value}%' </select>
如果本例子使用#{}则传入的字符串中必须有%号,而%是人为拼接在参数中,显然有点麻烦,如果采用${}在sql中拼接为%的方式则在调用mapper接口传递参数就方便很多。
再比如order by排序,如果将列名通过参数传入sql,根据传的列名进行排序,应该写为:
ORDER BY ${columnName}
如果使用#{}将无法实现此功能。
注意:${}不能防止sql注入,对系统安全性有很大的影响,如果使用${}建议传入参数尽量不让用户自动填写,即使要用户填写也要对填写的数据进行校验,保证安全性。
另外,当传递单个值时${}中填写的参数名称经过测试填写value不报错。
动态sql(重点)
Mybatis提供使用ognl表达式动态生成sql的功能。
If
<!--传递pojo综合查询用户信息 --> <select id="selectUserByUser" parameterType="user" resultType="user"> select * from user where 1=1 <if test="id!=null and id!=''"> and id=#{id} </if> <if test="username!=null and username!=''"> and username like '%${username}%' </if> </select>
注意要做不等于空字符串校验。
Where
上边的sql也可以改为:
<select id="selectUserByUser" parameterType="user" resultType="user"> select * from user <where> <if test="id!=null and id!=''"> and id=#{id} </if> <if test="username!=null and username!=''"> and username like '%${username}%' </if> </where> </select>
<where />可以自动处理第一个and。
foreach
向sql传递数组或List,mybatis使用foreach解析,如下:
传递List
传递List类型在编写mapper.xml没有区别,唯一不同的是只有一个List参数时它的参数名为list。
如下:
<select id="selectUserByList" parameterType="java.util.List"resultType="user"> select * from user <where> <!--传递List,List中是pojo --> <if test="list!=null"> <foreach collection="list" item="item" open="and id in(" separator="," close=")"> #{item.id} </foreach> </if> </where> </select>
传递数组(数组中是pojo):
<!--传递数组综合查询用户信息 --> <select id="selectUserByArray" parameterType="Object[]" resultType="user"> select * from user <where> <!--传递数组 --> <if test="array!=null"> <foreach collection="array" index="index" item="item" open="and id in(" separator="," close=")"> #{item.id} </foreach> </if> </where> </select>
sql只接收一个数组参数,这时sql解析参数的名称mybatis固定为array,如果数组是通过一个pojo传递到sql则参数的名称为pojo中的属性名。
index:为数组的下标。
item:为数组每个元素的名称,名称随意定义
open:循环开始
close:循环结束
separator:中间分隔输出
如果数组中是简单类型则写为#{item},不用再通过ognl获取对象属性值了。
Sql片段
需求
Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的,如下:
<!--传递pojo综合查询用户信息 --> <select id="selectUserByUser" parameterType="user" resultType="user"> select * from user <where> <if test="id!=null and id!=''"> and id=#{id} </if> <if test="username!=null and username!=''"> and username like '%${username}%' </if> </where> </select>
将where条件抽取出来:
<sql id="query_user_where"> <if test="id!=null and id!=''"> and id=#{id} </if> <if test="username!=null and username!=''"> and username like '%${username}%' </if> </sql>
使用include引用:
<select id="selectUserByUser" parameterType="user" resultType="user"> select * from user <where> <include refid="query_user_where"/> </where> </select>
注意:如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,如下:
<include refid="namespace.sql片段”/>
resultMap
当输出pojo的字段和sql查询出来的字段名称不对应时而还想用这个pojo类作为输出类型这时就需要使用resultMap了。
另外,resultMap也解决了一对一关联查询、一对多关联查询等常见需求。
创建Person类'
Public class Person { privateint id; private String name;// 用户姓名,名称和User表的字段名称不一样 private String sex;// 性别 private Date birthday;// 出生日期 private String addr;// 地址,名称和User表的字段名称不一样 private String detail;// 详细信息 private Float score;// 成绩 get/set。。。。
定义resultMap
在mapper.xml文件中定义resultMap:
<!-- resultMap定义 --> <resultMap type="cn.itcast.mybatis.po.Person" id="personmap"> <id property="id" column="id"/> <result property="name" column="username"/> <result property="addr" column="address"/> </resultMap>
<id />:此属性表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个<id />。
Property:表示person类的属性。
Column:表示sql查询出来的字段名。
Column和property放在一块儿表示将sql查询出来的字段映射到指定的pojo类属性上。
<result />:普通结果,即pojo的属性。
这里只将sql查询出来的字段与pojo属性名不一致的进行了定义,通过后边的测试pojo属性名和sql字段相同的自动进行映射。
Mapper.xml定义
<!--获取用户列表返回resultMap --> <select id="selectUserListResultMap" resultMap="personmap"> select * from user </select>
使用resultMap指定上边定义的personmap。
Mapper接口定义
public List<Person> selectUserListResultMap() throws Exception;
实际返回的类型是Person类型。
测试:
Public void testselectUserListResultMap() throws Exception{ //获取session SqlSession session = sqlSessionFactory.openSession(); //获限mapper接口实例 UserMapper userMapper = session.getMapper(UserMapper.class); User user = newUser(); user.setUsername("管理员"); //查询用户列表返回resultMap List<Person> list = userMapper.selectUserListResultMap(); System.out.println(list); //关闭session session.close(); }