一、 Indroduction
Mybatis是一款优秀的持久层框架。顺便插一句,框架是什么?框架被应用于很多领域,如建筑,机械。在软件工程中,框架(Framework)是整个或者部分系统的可重用设计,是一个可复用的设计构件。可重用性,使框架的好处不言而喻。框架使开发人员从一些基础工作和一般的细节处理中解放出来,可以集中精力于系统的业务逻辑设计。Mybatis支持定制化SQL,存储过程以及高级映射。Mybatis的使用免去了原始的JDBC代码,它还可以实现一定程度的自动生成。Mybatis使用xml或者注解配置pojo和数据库记录的映射。
二、 基本步骤
1. 创建web工程
2. 导入jar包和配置日志文件
3. 配置sqlMapConfig.xml
4. 创建pojo或者类似的domain类
5. 编写sql映射文件
6. 加载sql映射文件
7. 测试
8. 例子
配置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>
<!-- 和spring整合后 environments配置将废除-->
<environmentsdefault="development">
<environmentid="development">
<!-- 使用jdbc事务管理-->
<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="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 装载sql映射文件 -->
<mapperresource="User.xml"/>
</mappers>
</configuration>
创建pojo略,注意pojo属性与对应的表的字段的一一对应关系。
编写sql映射文件,注意命名空间的作用,作为映射文件内sql语句的标识
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间作用:做sql隔离 -->
<mappernamespace="test">
<!-- id:sql语句的标识,可以认为是sql要执行的方法名
parameterType:参数类型,全名或者别名
resultType:方法返回值的类型,可以为基本类型或者引用类型,全名或别名都可以
#{},#表示占位符,当参数为基本类型时,占位符里的值可以使用任意值占位,当参数为引用类型时,请根据引用类型的属性名填写
综上,形成pojo类型与数据库字段的关系映射
-->
<selectid="queryUserById"parameterType="java.lang.Integer"resultType="com.mybatis.pojo.User">
select * from user where id=#{haha}
</select>
</mapper>
测试,注意创建sql会话工厂,同时载入sqlMapConfig文件,以及sql会话调用相关方法,执行sql。
@Test
public voidtest1() throws Exception{
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
//创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建SqlSession
SqlSession sqlSession=factory.openSession();
//通过sql会话调用sql语句
User u=sqlSession.selectOne("test.queryUserById", 1);
System.out.println(u);
}
9. 其他sql业务
执行修改数据库操作的时候,mybatis会自动开启事务,请手动提交,操作,以提交事务。否则,不执行。
注意执行不同的业务,调用sql会话中相应的方法。
1) 根据姓名模糊查询
A. 使用#占位符
<selectid="queryUserByUsername"parameterType="java.lang.String"resultType="com.mybatis.pojo.User">
select * from user where username like#{username}
</select>
测试
List<User> u=sqlSession.selectList("test.queryUserByUsername","%王%");
B. 使用$拼接符
拼接符里面的内容为基本数据类型,那么参数的值必须为value。使用拼接符不能防止sql注入。
<!--
$拼接符的使用,拼接符不会自动加引号。如'hah${username}hh',拼接符里的内容为基本数据类型,参数值必须为value。拼接符不能防止sql注入。
-->
<selectid="queryUserByUsername"parameterType="java.lang.String"resultType="com.mybatis.pojo.User">
<!-- select *from user where username like #{username} -->
select * from user where usernamelike '%${value}%'
</select>
测试略
2) 插入操作
<!-- 插入数据库数据
参数列表,如果参数类中要传入的参数为引用类型的属性,请使用属性.属性,以此类推。
-->
<insertid="addUser"parameterType="com.mybatis.pojo.User">
insert into user values (null,#{username},#{birthday},#{sex},#{address})
</insert>
@Test
public voidtest3() throwsException{
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
//创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建SqlSession
SqlSession sqlSession=factory.openSession();
User u=new User();
u.setAddress("哈哈");
u.setBirthday(new Date());
u.setUsername("hei");
u.setSex("1");
sqlSession.insert("test.addUser",u);
sqlSession.commit();
System.out.println(u);
}
3) 删除数据库数据
<deleteid="deleteUserById"parameterType="int">
delete from user where id=#{id}
</delete>
@Test
public voidtest4() throws Exception{
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
//创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建SqlSession
SqlSession sqlSession=factory.openSession();
sqlSession.delete("test.deleteUserById",26);
sqlSession.commit();
}
4) 更新数据库数据
<updateid="resetUserById"parameterType="com.mybatis.pojo.User">
update user set username=#{username},birthday=#{birthday}where id=#{id}
</update>
@Test
public voidtest5() throws Exception{
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
//创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建SqlSession
SqlSession sqlSession=factory.openSession();
User u=new User();
u.setId(28);
u.setBirthday(new Date());
u.setUsername("kkss");
sqlSession.update("test.resetUserById",u);
sqlSession.commit();
System.out.println(u);
}
5) 关于插入操作时使用selectKey获得插入时创建的id。这里要数据库函数select last_insert_id();
<insertid="addUser"parameterType="com.mybatis.pojo.User">
<!--
这个selectKey一般用于插入操作,插入一般使用pojo传参,所以,可以将主键的值返回给这个pojo里面的属性接收
keyProperty:主键要返回的pojo类的属性,并且将主键值赋给这个属性,类型要一致
order:获得主键的时机,after之后,或者before之前
resultType:获得后返回的类型
-->
<selectKeykeyProperty="id"order="AFTER"resultType="String">
select last_insert_id();
</selectKey>
insert into user values (null,#{username},#{birthday},#{sex},#{address})
</insert>
@Test
public voidtest3() throwsException{
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
//创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建SqlSession
SqlSession sqlSession=factory.openSession();
User u=new User();
u.setAddress("哈哈");
u.setBirthday(new Date());
u.setUsername("hei");
u.setSex("1");
System.out.println(u.getId());
sqlSession.insert("test.addUser",u);
sqlSession.commit();
System.out.println(u.getId());
System.out.println(u);
}
6) 关于为数据库id字段插入uuid作为id。结合selectKey,使用order=”BEFORE”,在插入数据前产生uuid,请放入pojo。请使用数据库函数selectuuid();
</insert>
<!--
在插入数据前,通过数据库函数获得uuid,再使用selectKey获得这个uuid,赋值给pojo对应数据库id字段的属性。
-->
<insertid="addUser2"parameterType="com.mybatis.pojo.User2">
<!--
这个selectKey一般用于插入操作,插入一般使用pojo传参,所以,可以将主键的值返回给这个pojo里面的属性接收
keyProperty:主键要返回的pojo类的属性,并且将主键值赋给这个属性,类型要一致
order:获得主键的时机,after之后,或者before之前
resultType:获得后返回的类型
业务逻辑:在插入数据前,获得uuid放入pojo,插入时即可将uuid表示的id也插入。
-->
<selectKeykeyProperty="id"order="BEFORE"resultType="String">
select uuid();
</selectKey>
insert into user2 values (#{id},#{username},#{birthday},#{sex},#{address})
</insert>
@Test
public voidtestUuid() throwsException{
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
//创建sql会话工厂的实例,同时使用sqlSessionFactory读取配置文件
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂创建SqlSession
SqlSession sqlSession=factory.openSession();
User2 u=new User2();
u.setAddress("哈哈");
u.setBirthday(new Date());
u.setUsername("hei");
u.setSex("1");
System.out.println(u.getId());
sqlSession.insert("test.addUser2",u);
sqlSession.commit();
System.out.println(u.getId());
System.out.println(u);
}
三、 Dao层开发
(一) 原始的dao层开发
核心步骤:
1. 创建dao层接口和实现类
2. 编写sql映射xml
3. 在dao层实现类使用sql会话,实现业务
4. 为了节省资源,将SqlSessionFactory的创建放在更全局的位置
5. SqlSession由于是多线程的,为了避免线程干扰,SqlSession的作用域不可以无理由扩大,所以SqlSession最好定义在使用单个使用SqlSession的请求或方法里。
6. 例子
编写sql映射xml
略,同上
创建dao层接口和类,注意对SqlSessionFactory的处理
public interface UserDao {
public User queryUserById(intid);
public voidaddUser(User u);
}
public class UserDaoImpl implements UserDao{
//使用SqlSessionFactory进行sql会话
private SqlSessionFactorysqlSessionFactory;
public UserDaoImpl(SqlSessionFactorysqlSessionFactory){
this.sqlSessionFactory=sqlSessionFactory;
}
@Override
public User queryUserById(intid) {
SqlSession sqlSession=sqlSessionFactory.openSession();
User u=sqlSession.selectOne("user.queryUserById", 1);
return u;
}
}
创建service层类和接口
public interface UserService {
User queryUserById(intid);
}
public class UserServiceImpl implements UserService{
private staticSqlSessionFactory sqlSessionFactory;
private staticInputStream inputStream;
static {
try {
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
sqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);
} catch (IOExceptione) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private staticUserDao ud=new UserDaoImpl(sqlSessionFactory);
public User queryUserById(intid) {
return ud.queryUserById(id);
}
}
测试略
7. 其他数据库操作的例子,注意修改类操作,需要提交sql会话。
(二) 接口映射动态代理方式
这里出现了动态代理这个词。在spring的aop中,其底层采用的是动态代理,不管是jdk的还是cglib的动态代理实现,都有一个代理类的东西,代理委托对象实现某些业务。在这个mybatis的接口映射动态代理这里,既然是代理,就有委托对象和代理对象,委托对象是接口及其中的方法,代理对象是sql映射xml,相当于xml中直接实现了接口里的方法。本来接口,需要实现类实现接口的方法的,但是接口委托给xml做了,也可以看作xml代理了实现类的工作,然后实现类并没有创建出来,明确的说是xml代理了本应该由实现类做的工作。这样,在实现动态代理时,需要对应好接口和xml的相关参数。
接口与映射xml的对应要求:
1. 接口和xml需要同包同名。
2. Xml中的namespace为接口的全路径名称,这样当sqlMapConfig.xml装载了映射xml后,才能找到接口。实际上,是根据SqlSession获取接口,获取的同时传入这个接口的路径,在这两个过程中会试图建立接口和xml的连接关系,成功后则接口的实例可以调用自己的方法,并通过xml代理实现这个方法。
3. 接口的方法名与xml中相应的sql会话的id值一致
4. 接口的方法中的参数与相应的sql会话中的paremeterType的值一致
5. 接口的方法中的返回类型与相应的sql会话中的resultTyoe的值一致
6. 例子
创建接口类
public interface UserMapper {
public User queryUserById(intid);
}
创建xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间作用:做sql隔离 -->
<mappernamespace="com.mybatis.mapper.UserMapper">
<!-- id:sql语句的标识,可以认为是sql要执行的方法名
parameterType:参数类型,全名或者别名
resultType:方法返回值的类型,可以为基本类型或者引用类型,全名或别名都可以
#{},#表示占位符,当参数为基本类型时,占位符里的值可以使用任意值占位,当参数为引用类型时,请根据引用类型的属性名填写
综上,形成pojo类型与数据库字段的关系映射
-->
<selectid="queryUserById"parameterType="java.lang.Integer"resultType="com.mybatis.pojo.User">
select* from user where id=#{haha}
</select>
<!--
$拼接符的使用,拼接符不会自动加引号。如'hah${username}hh',拼接符里的内容为基本数据类型,参数值必须为value。拼接符不能防止sql注入。
-->
<selectid="queryUserByUsername"parameterType="java.lang.String"resultType="com.mybatis.pojo.User">
<!-- select* from user where username like #{username} -->
select * from user where usernamelike '%${value}%'
</select>
</mapper>
测试
public class TestMapper {
private SqlSessionFactorysqlSessionFactory;
private InputStreaminputStream;
{
try {
InputStream inputStream=Resources.getResourceAsStream("sqlMapConfig.xml");
sqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);
} catch (IOExceptione) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
public voidtest1(){
SqlSession sqlSession=sqlSessionFactory.openSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
System.out.println(UserMapper.class);
User u=userMapper.queryUserById(1);
System.out.println(u);
}
}
7. 关于增删改的操作。这些更新类型的操作需要sql会话提交,才能生效。例子略。
四、 sqlMapConfig.xml文件的一些配置
(一) propertyies属性配置
propertyies,用于配置连接数据库的相关信息,好处是分离代码,降低耦合。
配置数据库信息的文件db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=1234
修改sqlMapConfig.xml的配置
<!-- 配置连接池配置文件 -->
<propertiesresource="db.properties"></properties>
<environmentsdefault="development">
<environmentid="development">
<!-- 使用jdbc事务管理-->
<transactionManagertype="JDBC"/>
<!-- 数据库连接池-->
<dataSourcetype="POOLED">
<propertyname="driver"value="${jdbc.driver}"/>
<propertyname="url"value="${jdbc.url}"/>
<propertyname="username"value="${jdbc.username}"/>
<propertyname="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 |
map | Map |
使用typeAliases属性也可以定义别名
请注意sqlMapConfig.xml中标签的前后顺序,见xml的提示。
在sqlMapConfig.xml中定义别名
<typeAliases>
<!--
alias:别名
type:类型
-->
<typeAliasalias="haha"type="com.mybatis.pojo.User"></typeAlias>
</typeAliases>
使用别名
<selectid="queryUserById"parameterType="java.lang.Integer"resultType="haha">
select * from user where id=#{haha}
</select>
Mybatis提供了扫描包,自动定义别名的功能,将类名定义为别名,不区分大小写,一般采用驼峰表示法。
开启别名自动扫描
<typeAliases>
<packagename="com.mybatis.pojo"/>
</typeAliases>
(三) mapper映射器配置
在sqlMapConfig.xml中提供了3种方式加载映射文件
resource
class
package
<mappers>
<!-- 装载sql映射文件 -->
<mapperresource="User.xml"/>
<mapperresource="UserDao.xml"/>
<mapperclass="com.mybatis.mapper.UserMapper"/>
<packagename="com.mybatis.mapper"/>
</mappers>
五、 对象关系映射文件中sql语句的参数与返回值
(一) Sql语句参数类型
缺省parameterType,表示sql映射的方法无参。
1. 基本数据类型
<selectid="queryUserById"parameterType="java.lang.Integer"resultType="user">
select * from user where id=#{haha}
</select>
占位符的值可以任意
2. 未使用引用类型属性的引用数据类型
<updateid="resetUserById"parameterType="com.mybatis.pojo.User">
update user set username=#{username},birthday=#{birthday}where id=#{id}
</update>
注意:占位符的值与引用类型属性的对应一致
3. 使用引用类型属性的引用数据类型
这种类型,一般称为vo。Vo一般用于商业逻辑层和表示层。使用vo的好处,降低耦合,提高内聚。
例子:
编写映射sql语句
<!-- 使用vo的方式 -->
<selectid="queryUserByUserAndSex"parameterType="com.mybatis.pojo.QueryVo"resultType="user">
select * from user where usernamelike '%${user.username}%' and sex=#{user.sex}
</select>
测试
@Test
public voidtest4(){
SqlSession sqlSession=sqlSessionFactory.openSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
User u=new User();
u.setUsername("王");
u.setSex("2");
QueryVo qv=new QueryVo();
qv.setUser(u);
User qu=userMapper.queryUserByUserAndSex(qv);
System.out.println(qu);
}
(二) Sql语句返回类型
1. Void
缺省resultType表示sql映射的方法无返回值。
<updateid="resetUserById"parameterType="com.mybatis.pojo.User">
update user set username=#{username},birthday=#{birthday}where id=#{id}
</update>
2. 引用数据类型
<selectid="queryUserById"parameterType="java.lang.Integer"resultType="user">
select * from user where id=#{haha}
</select>
3. 基本数据类型
<!-- 返回基本数据类型 -->
<selectid="queryUserCount"resultType="int">
select count(*) from user
</select>
4. 集合
请使用集合的泛型作为返回值
<selectid="queryUserByUsername"parameterType="java.lang.String"resultType="com.mybatis.pojo.User">
<!-- select* from user where username like #{username} -->
select * from user where usernamelike '%${value}%'
</select>
六、 Sql语句的控制流程标签的使用
使用控制流程标签可以实现sql的动态效果
1. if
<selectid="queryUserByOptions"parameterType="user"resultType="user">
select * from user where 1=1
<iftest="username!=nulland username!=''">
and username like '%${username}%'
</if>
<iftest="sex!=null andsex!=''">
and sex=#{sex}
</if>
</select>
使用where标签后
<selectid="queryUserByOptions"parameterType="user"resultType="user">
select * from user
<!-- where 自动添加where条件以及去掉where关键字后的and -->
<where>
<iftest="username!=nulland username!=''">
and username like '%${username}%'
</if>
<iftest="sex!=null andsex!=''">
and sex=#{sex}
</if>
</where>
</select>
使用sql标签封装sql语句,并使用include标签调用sql标签的id后
<sql id="userOptions">
<!-- where 自动添加where条件以及去掉where关键自后的and -->
<where>
<iftest="username!=nulland username!=''">
and username like '%${username}%'
</if>
<iftest="sex!=null andsex!=''">
and sex=#{sex}
</if>
</where>
</sql>
<selectid="queryUserByOptions"parameterType="user"resultType="user">
select * from user
<includerefid="userOptions"></include>
</select>
2. foreach
主要参数:
collection:要循环的集合的名称
item:每次循环将结果存放为的值
open:循环开始的语句
close:循环结束的语句
separator:每次循环的值的分隔符
例子:
<!-- 使用foreach组织数组式条件 -->
<selectid="queryUserByIds"parameterType="queryVo"resultType="user">
select * from user
<where>
<iftest="ids!=null">
<!--
collection:要循环的集合的名称
item:每次循环将结果存放为的值
open:循环开始的语句
close:循环结束的语句
separator:每次循环的值的分隔符
-->
<foreachcollection="ids"item="id"open="id in ("close=")"separator=",">
#{id}
</foreach>
</if>
</where>
</select>
测试略
使用sql标签后
<sqlid="idsOption">
<where>
<iftest="ids!=null">
<!--
collection:要循环的集合的名称
item:每次循环将结果存放为的值
open:循环开始的语句
close:循环结束的语句
separator:每次循环的值的分隔符
-->
<foreachcollection="ids"item="id"open="id in ("close=")"separator=",">
#{id}
</foreach>
</if>
</where>
</sql>
<!-- 使用foreach组织数组式条件 -->
<selectid="queryUserByIds"parameterType="queryVo"resultType="user">
select * from user
<includerefid="idsOption"></include>
</select>
七、 多表关联查询的映射关系
(一) 关联查询的一对一关系
1. 方式一:非主动设置,Po类属性与数据库查询表的字段根据名称一一对应。
注意上述的表为查询表,而非原表。
例子:
创建po类对应数据查询表字段,利用了继承,简化了代码,提高了重用
public class OrderOfUser extends Orders{
private intuid;
private Stringusername;//用户姓名
private Stringsex;//性别
private Datebirthday;//生日
private Stringaddress;//地址
public intgetUid() {
return uid;
}
public voidsetUid(intuid){
this.uid =uid;
}
public String getUsername() {
return username;
}
public voidsetUsername(String username){
this.username =username;
}
public String getSex() {
return sex;
}
public voidsetSex(String sex){
this.sex =sex;
}
public Date getBirthday() {
return birthday;
}
public voidsetBirthday(Date birthday){
this.birthday =birthday;
}
public String getAddress() {
return address;
}
public voidsetAddress(String address){
this.address =address;
}
@Override
public String toString() {
return "OrderOfUser [uid=" + uid + ", username="+ username+ ", sex="+ sex+ ", birthday=" + birthday
+ ", address=" + address + "]" +"\n";
}
}
编写sql语句映射
<!-- 联合查询的一对一关系 -->
<selectid="queryOrder"resultType="orderOfUser">
SELECT o.*,u.id uid,u.username,u.address,u.sex,u.birthdayFROM orders o,USER u WHERE o.user_id=u.id
</select>
2. 方式二:主动设置po类和数据库查询表的映射关系
当sql语句返回的类型为引用类型,并且查询表中的字段为返回的引用类型的引用类型的属性的时候,可以手动设置查询表字段与返回类型的引用数据类型的映射关系。
语法:
<select id=””parameterType=”” resultMap=”唯一标识”>
……
</select>
<resultMap id=”唯一标识” type=”接收sql返回值的类型”>
<id column=”” property=”” />
<!- - 一般认为这个id为主键字段与模型领域属性的映射关系专用的,经过尝试,将result换成id,或者id换成result,也可以得到一样的结果-- >
<result column=”” property=”” />
<result column=”” property=”” />
<!- -association设置po类中引用类型属性与查询表字段的映射关系
Type:设置引用类型属性的类型
Property:设置引用类型属性的名称
-- >
<association property=”” type=””>
<id column=”” property=”” />
<!- - 传说这个id为主键字段与模型领域属性的映射关系专用的,经过尝试,将result换成id,或者id换成result,也可以得到一样的结果-- >
<resultcolumn=”” property=”” />
<resultcolumn=”” property=”” />
</association>
</resultMap>
例子:
创建po类
public class User {
private intid;
private Stringusername;//用户姓名
private Stringsex;//性别
private Datebirthday;//生日
private Stringaddress;//地址
public intgetId() {
return id;
}
public voidsetId(intid) {
this.id =id;
}
public String getUsername() {
return username;
}
public voidsetUsername(String username){
this.username =username;
}
public String getSex() {
return sex;
}
public voidsetSex(String sex){
this.sex =sex;
}
public Date getBirthday() {
return birthday;
}
public voidsetBirthday(Date birthday){
this.birthday =birthday;
}
public String getAddress() {
return address;
}
public voidsetAddress(String address){
this.address =address;
}
@Override
public String toString() {
return "User [id=" + id + ", username="+ username+ ", sex="+ sex
+ ", birthday=" + birthday + ", address="+ address+ "]"+"\r\n";
}
}
public class Orders {
private Integerid;
private IntegeruserId;
private Stringnumber;
private Datecreatetime;
private Stringnote;
private Useruser;
public User getUser() {
return user;
}
public voidsetUser(User user){
this.user =user;
}
public Integer getId() {
returnid;
}
public void setId(Integer id) {
this.id =id;
}
public Integer getUserId() {
returnuserId;
}
public void setUserId(Integer userId) {
this.userId =userId;
}
public String getNumber() {
returnnumber;
}
public void setNumber(String number) {
this.number =number==null?null:number.trim();
}
public Date getCreatetime() {
returncreatetime;
}
public void setCreatetime(Date createtime) {
this.createtime =createtime;
}
public String getNote() {
returnnote;
}
public void setNote(String note) {
this.note =note==null?null:note.trim();
}
@Override
public String toString() {
return "Orders [id=" + id + ", userId="+ userId+ ", number=" + number+ ", createtime=" + createtime
+ ", note=" + note + ", user="+ user+ "]";
}
}
<!-- 手动设置返回类中引用类型属性与查询表字段的映射关系 -->
<resultMaptype="orders"id="orderOfUserMap">
<!--
id:结果映射的标识
type:sql返回类型
-->
<!--
id标签,指定查询表主键与javapo类的映射关系
result,指定其他字段与po类的映射关系
-->
<idcolumn="id"property="id"/>
<resultcolumn="user_id"property="userId"/>
<resultcolumn="number"property="number"/>
<resultcolumn="createtime"property="createtime"/>
<resultcolumn="note"property="note"/>
<!--
association:指定返回po类的引用类型属性与属性值的对应关系
-->
<associationproperty="user"javaType="user">
<resultcolumn="username"property="username"/>
<resultcolumn="uid"property="id"/>
<resultcolumn="address"property="address"/>
<resultcolumn="sex"property="sex"/>
<resultcolumn="birthday"property="birthday"/>
</association>
</resultMap>
<selectid="queryOrder2"resultMap="orderOfUserMap">
SELECT o.*,u.id uid,u.username,u.address,u.sex,u.birthdayFROM orders o,USER u WHERE o.user_id=u.id
</select>
测试略
(二) 关联查询的一对多关系
一对多的关系,指主表的id对用的关联表中会产生多个结果的关系。
比如,一个学生表,一个课程表,学生表中学生id,关联课程表中学生id外键的时候,可能有多个课程的id对应这个学生的id,这样就形成了一对多的关系。
一对多只能通过手动设置的方式实现。
语法:
<select id=””parameterType=”” resultMap=”唯一标识”>
……
</select>
<resultMap id=”唯一标识” type=”接收sql返回值的类型”>
<id column=”” property=”” />
<!- - 一般认为这个id为主键字段与模型领域属性的映射关系专用的,经过尝试,将result换成id,或者id换成result,也可以得到一样的结果-- >
<result column=”” property=”” />
<result column=”” property=”” />
<!- -collection设置 po类中集合类型属性与查询表字段的映射关系,这个集合类型就是多的一方
Property:集合类型属性在其类中的名称
ofType:集合的泛型的类型
-- >
<collection property=”” ofType=””>
<id column=”” property=”” />
<!- - 传说这个id为主键字段与模型领域属性的映射关系专用的,经过尝试,将result换成id,或者id换成result,也可以得到一样的结果-- >
<resultcolumn=”” property=”” />
<resultcolumn=”” property=”” />
</collection>
</resultMap>
例子:
创建返回类型的类,也就是一的一方,注意将多的一方作为泛型的集合定义为返回类的属性
关键代码部分:
private List<Orders>orders;
public List<Orders> getOrders() {
return orders;
}
public voidsetOrders(List<Orders> orders) {
this.orders =orders;
}
编写sql语句的一对多映射配置
<!-- 联合查询的一对多映射关系 -->
<selectid="queryOrder3"resultMap="userOfOrderMap">
SELECT u.*,o.id oid,o.user_id,o.number,o.createtime,o.noteFROM orders o,USER u WHERE o.user_id=u.id
</select>
<!-- 设置结果映射 -->
<resultMapid="userOfOrderMap"type="user">
<idcolumn="id"property="id"/>
<resultcolumn="username"property="username"/>
<resultcolumn="address"property="address"/>
<resultcolumn="sex"property="sex"/>
<resultcolumn="birthday"property="birthday"/>
<!-- collection用于设置po类中集合类属性,也就是对应的多的一方的映射关系
请注意声明集合泛型的类型时,使用ofType
-->
<collectionproperty="orders"ofType="orders">
<idcolumn="oid"property="id"/>
<resultcolumn="user_id"property="userId"/>
<resultcolumn="number"property="number"/>
<resultcolumn="createtime"property="createtime"/>
<resultcolumn="note"property="note"/>
</collection>
</resultMap>
八、 Spring整合mybatis
整合spring的意义在于促进低耦合,高内聚。将能交给spring管理的交给spring管理,因为spring存在的意义之一就是IoC。所以,mybatis中的类以及映射xml文件都可以给spring。具体来说就是
SqlSessionFactory交由springbean组件实现;
SqlSession由spring创建;
映射动态代理形式,从spring获得代理对象;
数据库连接交给spring实现。
整合步骤:
1. 创建一个web工程
2. 导入需要的jar
Spring的jar包,mybatis的jar包,spring整合mybatis的jar包,mysql驱动包,连接池的jar包。
3. Mybatis配置文件sqlMapConfig.xml
4. Spring核心配置文件applicationContext.xml
5. 编写dao层接口类或者mappersql语句文件
6. 创建pojo
7. 测试
8. 例子
1) Dao层开发的方式
注意dao层开发中,可以使用dao层类继承SqlSessionDaoSupport的方式,简化开发。
Mybatis配置文件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>
<propertiesresource="db.properties"></properties>
<typeAliases>
<packagename="com.mybatis.pojo"></package>
</typeAliases>
<mappers>
<mapperresource="user.xml"></mapper>
<!--
在spring中配置之后,在我们的mybatis中,就不需要去自动扫描
-->
<!-- <packagename="com.mybatis.mapper"></package> -->
</mappers>
</configuration>
Spring核心配置文件applicationContext.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 加载配置文件 -->
<context:property-placeholderlocation="classpath:db.properties"/>
<!-- 数据库连接池 -->
<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<propertyname="driverClassName"value="${jdbc.driver}"/>
<propertyname="url"value="${jdbc.url}"/>
<propertyname="username"value="${jdbc.username}"/>
<propertyname="password"value="${jdbc.password}"/>
<propertyname="maxActive"value="10"/>
<propertyname="maxIdle"value="5"/>
</bean>
<!-- mapper配置 -->
<!-- 让spring管理sqlsessionfactory使用mybatis和spring整合包中的 -->
<beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 -->
<propertyname="dataSource"ref="dataSource"/>
<!-- 加载mybatis的全局配置文件 -->
<propertyname="configLocation"value="classpath:sqlMapConfig.xml"/>
</bean>
<!-- 装载dao层实现类的bean组件,同时注入sql会话工厂 -->
<beanid="userDao"class="com.mybatis.dao.UserDaoImpl">
<propertyname="sqlSessionFactory"ref="sqlSessionFactory"/>
</bean>
</beans>
Dao层接口和类,注意类继承SqlSessionDaoSupport简化开发
public interface UserDao {
public User queryUserById(intid);
}
public class UserDaoImpl extends SqlSessionDaoSupportimplements UserDao{
public User queryUserById(intid) {
SqlSession sqlSession=this.getSqlSession();
User u=sqlSession.selectOne("user.queryUserById",id);
return u;
}
}
创建pojo略,测试
@Test
public voidtest1(){
ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");
UserDao ud=(UserDao)ac.getBean("userDao");
User u=ud.queryUserById(1);
System.out.println(u);
}
2) Mapper动态代理的形式
核心步骤:
A. 创建sql会话接口映射包,创建接口和mapper映射文件
B. Spring核心配置文件中,装配代理类的bean组件
C. 例子
接口映射包内容
public interface UserMapper {
public User queryUserById(intid);
}
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间作用:做sql隔离
之后会有规范
-->
<mappernamespace="com.mybatis.mapper.UserMapper">
<!-- 根据id查询用户 -->
<selectid="queryUserById"parameterType="int"resultType="user">
select * from user where id=#{id}
</select>
</mapper>
配置代理对象的bean组件
<!-- 装配sql会话映射的接口,即委托对象的代理bean -->
<beanclass="org.mybatis.spring.mapper.MapperFactoryBean">
<propertyname="mapperInterface"value="com.mybatis.mapper.UserMapper"/>
<propertyname="sqlSessionFactory"ref="sqlSessionFactory"/>
</bean>
测试
public void test1(){
ApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");
UserMapperuserMapper=ac.getBean(UserMapper.class);
User user=userMapper.queryUserById(1)
System.out.println(user);
}
D. 关于配置dao接口代理对象bean组件的自动扫描
通过MapperScanConfigurer类开启委托对象的代理对象bean组件的自动扫描装载功能。
<!-- 开启sql会话映射接口,代理bean的自动扫描
扫描包中的接口的bean的id赋值为接口名首字母小写。
sqlSessionFactory,也自动加载。不配置。
-->
<beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer">
<propertyname="basePackage"value="com.mybatis.mapper"/>
</bean>
这样可以扫描加载后,在业务流程中得到mapper的bean的id,直接使用bean。
在spring中开启代理对象bean组件的扫描后,可省去mybatis主配置文件中的扫描映射源的功能。
九、 逆向工程
使用官方网站的mapper自动生成工具mybatis-generator-core-1.3.2来生成po类和mapper映射文件。mybatis官方提供逆向工程,可以使用它通过数据库中的表来自动生成Mapper接口和映射文件(单表增删改查)和Po类。
步骤:
(一) 导入jar包
(二) 装配生成文件generatorConfig.xml
1. 配置数据库链接信息
Mysql版
<jdbcConnection
driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="admin">
</jdbcConnection>
Oracle版
<jdbcConnection
driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:oracle"
userId="oracle"
password="oooo">
</jdbcConnection>
2. 配置po类的目标文件包
<javaModelGeneratortargetPackage="com.***.***.po"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<propertyname="enableSubPackages"value="false"/>
<!-- 从数据库返回的值被清理前后的空格 -->
<propertyname="trimStrings"value="true"/>
</javaModelGenerator>
3. 配置mapper映射文件和接口的目标文件包
<sqlMapGeneratortargetPackage="com.***.***.dao"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<propertyname="enableSubPackages"value="false"/>
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGeneratortype="XMLMAPPER"
targetPackage="com.***.***.dao"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<propertyname="enableSubPackages"value="false"/>
</javaClientGenerator>
4. 指定数据库表
Mysql版
<tabletableName="items"></table>
<tabletableName="orders"></table>
<tabletableName="orderdetail"></table>
<tabletableName="user"></table>
Oracle版
<table schema=""tableName="sys_user"></table>
<tableschema="" tableName="sys_role"></table>
<tableschema="" tableName="sys_permission"></table>
<tableschema="" tableName="sys_user_role"></table>
<tableschema="" tableName="sys_role_permission"></table>
<!-- 有些表的字段需要指定java类型 -->
<table schema=""tableName="">
<columnOverride column=""javaType="" />
</table>
5. 完整版配置文件
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEgeneratorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<contextid="testTables"targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是: false:否 -->
<propertyname="suppressAllComments"value="true"/>
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnectiondriverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"userId="root"
password="admin">
</jdbcConnection>
<!-- <jdbcConnectiondriverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg">
</jdbcConnection> -->
<!-- 默认false,把JDBC DECIMAL和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL和
NUMERIC 类型解析为java.math.BigDecimal-->
<javaTypeResolver>
<propertyname="forceBigDecimals"value="false"/>
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGeneratortargetPackage="com.***.***.pojo"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<propertyname="enableSubPackages"value="false"/>
<!-- 从数据库返回的值被清理前后的空格 -->
<propertyname="trimStrings"value="true"/>
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGeneratortargetPackage="com.***.***.dao"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<propertyname="enableSubPackages"value="false"/>
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGeneratortype="XMLMAPPER"
targetPackage="com.***.***.dao"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<propertyname="enableSubPackages"value="false"/>
</javaClientGenerator>
<!-- 指定数据库表 -->
<tabletableName="items"></table>
<tabletableName="orders"></table>
<tabletableName="orderdetail"></table>
<tabletableName="user"></table>
<!-- <table schema=""tableName="sys_user"></table>
<table schema=""tableName="sys_role"></table>
<table schema=""tableName="sys_permission"></table>
<table schema=""tableName="sys_user_role"></table>
<table schema=""tableName="sys_role_permission"></table> -->
<!-- 有些表的字段需要指定java类型
<table schema=""tableName="">
<columnOverridecolumn="" javaType="" />
</table> -->
</context>
</generatorConfiguration>
注意:配置文件要放在工程目录下。也就是和src文件包同级的位置。
(三) 使用java类生成映射文件和po类文件
pubic class GeneratorSqlMap{
public void generator()throws Exception{
List<String> warnings = newArrayList<String>();
boolean overwrite =true;
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = newConfigurationParser(warnings);
Configuration config =cp.parseConfiguration(configFile);
DefaultShellCallback callback = newDefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = newMyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
public static void main(String[] args)throws Exception {
try {
GeneratorSqlMap generatorSqlMap = new GeneratorSqlMap();
generatorSqlMap.generator();
} catch (Exception e) {
e.printStackTrace();
}
}
}
(四) Copy使用生成的文件。注意前后复制时,文件目录名一致的问题。