MyBatis是对数据访问层即Dao层的框架。
对于重复的Dao层代码,用MyBatis来进行实现。底层是对JDBC的封装。
一、引入jar包
Maven仓库的引用。https://mvnrepository.com/artifact/org.mybatis/mybatis
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
二、创建mybatis配置文件
在src/main/resources即根目录下创建mybatis-config.xml(名字随意,尽量有意义)
添加如下声明信息,这是语句检查器,能够限制我们写的代码。
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
并且可以复制链接http://mybatis.org/dtd/mybatis-3-config.dtd下载dtd文件,在Eclipse下打开Window->Preferences->XML->XML Catalog里选择Add再选择File System将本地的dtd文件导入。
在Key type选择URI或是System ID都可以,在Key里填入http://mybatis.org/dtd/mybatis-3-config.dtd。
这样在编辑xml时就有提示词了。
三、配置数据库连接池
在mybatis-config.xml里写入
<configuration>
<typeAliases>
<package name="com.neusoft.busmis.security.model"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/busmis?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="poolMaximumActiveConnections" value="5"/>
<property name="poolMaximumIdleConnections" value="1"/>
<property name="poolTimeToWait" value="3000"/>
</dataSource>
</environment>
<environment id="oracle">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:busmis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="poolMaximumActiveConnections" value="5"/>
<property name="poolMaximumIdleConnections" value="1"/>
<property name="poolTimeToWait" value="3000"/>
</dataSource>
</environment>
<environment id="product">
<transactionManager type="JDBC"/>
<dataSource type="JNDI">
<property name="data_source" value="java:/comp/env/mysql3306busmis-c3p0"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/security/IUserDao.xml"/>
</mappers>
</configuration>
配置属性里要按如下顺序写入。
typeAliases设置包下类对象的别名,
(1)用<typeAlias type="com.neusoft.busmis.security.model.UserModel" alias="userModel"></typeAlias>
(2)用package name扫描包里的所有类。创建类的对象,默认命名为首字母小写,其他不变。
(3)也可以在Model类里用@Alias("name")来自定义别名。
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
在environments里嵌套多个environment来配置数据库连接池。
environments的default属性:任一下级的environment的id属性来选择连接哪个数据库连接池。
environment的id属性:识别各个environment的名字,随意填写。
transactionManager的type属性:JDBC或Managed,JDBC表示JDBC原生事务;Managed表示把事务管理转交给其他容器,可以转交给像Spring这种有事务管理功能的容器,底层实现是setAutoMapping(false);
dataSource的type属性:POOLED或UNPOOLED或JNDI,POOLED表示使用连接池,连接池可以提升系统运行效率;UNPOOLED表示不使用连接池,与直接使用JDBC一个意思;JNDI(JAVA目录命名接口)则使用外部配置数据源,一般是在tomcat里的context.xml里添加数据库信息。
properties里driver写数据库驱动,jdbc用新的com.mysql.cj.jdbc.Driver;url写数据库地址,注意&要用&使用;username和password就不说了;基本的就这四个,其他更多的属性可参考官方文档按需添加,http://www.mybatis.org/mybatis-3/zh/configuration.html#environments
mappers里嵌套多个mapper映射信息,用mapper resource写接口xml的路径,用mapper url写接口xml的本地路径,用mapper class写接口的包名和接口名,用package name写接口的包名,可扫描多个接口。后两种都需要在接口里添加@Mapper注解,并将Sql语句注解到各个接口方法里。
四、MVC
如有一个表userinfo,表数据随意添加。
create table UserInfo (
USERID varchar(20) primary key,
UserPASSWORD varchar(20),
UserNAME varchar(50),
AGE int(2)
);
1、创建model类,@Alias是创建各个Model类对象的引用别名(如User相当于UserModel User = new UserModel()),如不写这句,默认为userModel。
@Data只是Lombok的注解,Lombok实现model类get/set方法,减少代码量。
最好实现序列化接口。
package com.neusoft.busmis.security.model;
import java.io.Serializable;
import org.apache.ibatis.type.Alias;
import lombok.Data;
@Alias("User")
@Data
public class UserModel implements Serializable {
private String userid = null;
private String userpassword = null;
private String username = null;
private int age = 0;
}
2、创建Dao层接口
package com.neusoft.busmis.security.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.neusoft.busmis.security.model.UserModel;
@Mapper
public interface IUserDao {
//C方法
public void create(UserModel userModel)throws Exception;
//U方法
public void update(UserModel userModel)throws Exception;
//D方法
public void delete(UserModel userModel)throws Exception;
//R方法-取得列表
public List<UserModel> selectListByAll() throws Exception;
//R方法-取得列表,有分页 start起始记录,rows取得个数
public List<UserModel> selectListByAllWithPage(@Param("start")int start, @Param("rows")int rows) throws Exception;
//R方法-取得单个对象
public UserModel selectById(String id) throws Exception;
}
在根目录下创建mappers文件夹,再创建接口xml文件,一样通过dtd文件按上述方法可获得提示。
cache表示使用二级缓存,这里相对应的类一定要实现序列号接口,select语句都会缓存,这样下次执行相同的语句时会更快些;而insert、update、delete都不会缓存,但最好在它们的标签里添加属性flushcache="true"来清空缓存。
namespace表示该xml的包名,写实现的接口的包名+接口名。
parameterType属性表示传入参数的类型,也可不写parameterType,因为mybatis会自动识别。
然后在Sql语句时通过#{}获取参数内容。
(1)#{}里可以使用索引,从0开始,#{0}表示第一个参数;
(2)也可以使用#{param1}表示第一个参数;
(3)如果只有一个参数(基本类型或String),mybatis对#{}里的内容没有要求,只要有写内容即可。
(4)如果参数是对象,用法是#{属性名};
(5)如果参数是map,用法是#{key}。
不过parameter在处理多个参数的情况时,用上述所说的索引可以解决意外,在Dao接口方法使用@Param注解标识各个参数。
@Param的底层实现:是将@Param("")的字符串作为map的key,然后参数值作为map的value,将map传过去xml里,通过#{key}来获取多个参数。
还有另一种获取参数的形式${},Sql执行后#{}会变成?,然后将参数代替?;而${}是进行字符串拼接,不使用?,默认找${内容}内容的get/set方法,如果写数字,就是一个数字。
resultType属性表示返回的类型,这里写通过Alias注解创建的对象类型。
<?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="com.neusoft.busmis.security.dao.IUserDao">
<cache/>
<insert id="create" flushCache="true">
insert into userinfo values (#{userid},#{userpassword},#{username},#{age})
</insert>
<update id="update" flushCache="true">
update userinfo set UserName=#{username},age=#{age} where USERID=#{userid}
</update>
<delete id="delete" flushCache="true">
delete from UserInfo where userid=#{userid}
</delete>
<select id="selectListByAll" resultType="User">
select * from userinfo
</select>
<select id="selectListByAllWithPage" resultType="User">
select * from userinfo limit #{start},#{rows}
</select>
<select id="selectById" resultType="User">
select * from userinfo where userid=#{userid}
</select>
</mapper>
3、Service层,这里只写了查询方法。
package com.neusoft.busmis.security.service;
import java.util.List;
import com.neusoft.busmis.security.model.UserModel;
public interface IUserService {
//取得所有用户列表
//R方法-取得列表
public List<UserModel> getListByAll() throws Exception;
//R方法-取得列表,分页
public List<UserModel> getListByAllWithPage(int rows, int page) throws Exception;
//R方法-取得单个对象
public UserModel getById(String id) throws Exception;
}
实现类,mybatis-config.xml用工厂模式来创建SqlSession。
package com.neusoft.busmis.fatory;
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;
public class MyBatisFactory {
private static SqlSessionFactory ssf = null;
static{
String resource = "mybatis-config.xml";
InputStream inputStream;
try {
inputStream = Resources.getResourceAsStream(resource);
ssf = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
public static SqlSession getSession() {
return ssf.openSession();
}
}
package com.neusoft.busmis.security.service.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.neusoft.busmis.fatory.MyBatisFactory;
import com.neusoft.busmis.security.dao.IUserDao;
import com.neusoft.busmis.security.model.UserModel;
import com.neusoft.busmis.security.service.IUserService;
public class UserServiceImpl implements IUserService {
@Override
public List<UserModel> getListByAll() throws Exception {
SqlSession session = MyBatisFactory.getSession();
IUserDao userDao = session.getMapper(IUserDao.class);
List<UserModel> list = userDao.selectListByAll();
session.commit();
session.close();
return list;
}
@Override
public UserModel getById(String id) throws Exception {
SqlSession session = MyBatisFactory.getSession();
IUserDao userDao = session.getMapper(IUserDao.class);
UserModel um = userDao.selectById(id);
session.commit();
session.close();
return um;
}
//分页查询
@Override
public List<UserModel> getListByAllWithPage(int rows, int page) throws Exception {
SqlSession session = MyBatisFactory.getSession();
IUserDao userDao = session.getMapper(IUserDao.class);
List<UserModel> list = userDao.selectListByAllWithPage(rows*(page-1), rows);
session.commit();
session.close();
return list;
}
}
注:这里seesion的运用,如果是使用getMapper()方法获得Dao接口的实现时,xml的namespace必须使用对应接口的包名+接口名,而且接口要有增删改查的方法,方法名对应的xml里增删改查标签的id。getMapper()的实现使用的是JDK的动态代理设计模式,面向接口的代理设计模式(必须要有接口)
如果只是用session的select、insert、update内置的方法,就没那么多要求,接口也可以不提供方法,包名也可以随意取,当session.select()的参数需要提供xml的包名+方法id,还有传入的数据。
测试:
package com.neusoft.busmis.test;
import java.util.List;
import com.neusoft.busmis.security.model.UserModel;
import com.neusoft.busmis.security.service.IUserService;
import com.neusoft.busmis.security.service.impl.UserServiceImpl;
public class TestUser {
public static void main(String[] args) {
IUserService us = new UserServiceImpl();
try {
List<UserModel> list = us.getListByAll();
for(UserModel um:list) {
System.out.println(um.getUserid());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
五、关联表的处理
有如下表
-- 系统用户表
create table UserInfo (
USERID varchar(20) primary key,
UserPASSWORD varchar(20),
UserNAME varchar(50),
AGE int(2)
);
-- 系统角色表
create table Roles (
RNO int(4) primary key auto_increment,
RNAME varchar(20)
);
-- 用户角色关联表
create table UserRole (
USERID varchar(20) references UserInfo(USERID),
RNO int(4) references Roles(RNO),
primary key (USERID,RNO)
);
-- 系统模块表
create table SystemModule(
MNO int(10) primary key,
MName varchar(50)
);
-- 系统功能表
create table SystemFunction(
FUNNO int(10) primary key,
MNO int(10) references SystemModule(MNO),
FUNNAME varchar(50),
FUNURL varchar(100)
);
-- 系统角色与功能模块关联表
create table RoleModule (
RNO int(4) references Roles(RNO),
MNO int(10) references SystemModule(MNO),
primary key (RNO,MNO)
);
表信息自己定义。
<resultMap type="Function" id="FunctionResultMap">
<id property="funno" column="funno"/>
<result property="funname" column="funname"/>
<result property="funurl" column="funurl"/>
</resultMap>
resulttype基本上用于select语句的返回类型,但由于*的关系,必须保证model里定义的属性与数据库表的属性一致才能使用*,否则只能将数据库的属性取别名的方式来取数据。
resultmap的使用:与resultype类似,但比resulttype更好,更实用。使用resultmap就可以使用*来执行select语句以及处理有关联的数据库表。
关联的数据库表有一对多、多对一和多对多。
一对多、多对一:如上面表里的SystemFunction和SystemModule两个表,Function是多方,Module是一方。
Function的Model类要有Module类,Module的Model类要有Function类列表。
package com.neusoft.busmis.security.model;
import org.apache.ibatis.type.Alias;
import lombok.Data;
@Alias("Function")
@Data
public class FunctionModel implements Serializable {
private int funno;
private String funname;
private String funurl;
private ModuleModel module;
}
package com.neusoft.busmis.security.model;
import java.util.List;
import org.apache.ibatis.type.Alias;
import lombok.Data;
@Alias("Module")
@Data
public class ModuleModel implements Serializable {
private int mno;
private String mname;
//关联
private List<FunctionModel> functions;
}
多对多:如上面表里的Roles和SystemMod
ule,User和Roles,多对多在数据库里需要另一个关联表来实现这种关联。
Module的Model类要有Roles类列表,Roles的Model类要有Module类列表;User的Model类要有Roles类列表,Roles的Model类要有User类列表。
package com.neusoft.busmis.security.model;
import java.util.List;
import org.apache.ibatis.type.Alias;
import lombok.Data;
@Alias("Module")
@Data
public class ModuleModel implements Serializable {
private int mno;
private String mname;
//关联
private List<FunctionModel> functions;
private List<RoleModel> roles;
}
package com.neusoft.busmis.security.model;
import java.util.List;
import org.apache.ibatis.type.Alias;
import lombok.Data;
@Alias("Role")
@Data
public class RoleModel implements Serializable {
private int rno;
private String rname;
private List<UserModel> users;
private List<ModuleModel> modules;
}
package com.neusoft.busmis.security.model;
import java.io.Serializable;
import java.util.List;
import org.apache.ibatis.type.Alias;
import lombok.Data;
@Alias("User")
@Data
public class UserModel implements Serializable {
private String userid = null;
private String userpassword = null;
private String username = null;
private int age = 0;
private List<RoleModel> roles;
}
在Dao层接口的映射文件写映射信息。
多对一的关联:Function表通过属性mno外键关联Module表,如要通过mno取得Module表的信息,需要在resultmap写association标签。
<mapper namespace="com.neusoft.busmis.security.dao.IFunctionDao">
<resultMap type="Function" id="FunctionResultMap">
<id property="funno" column="funno"/>
<result property="funname" column="funname"/>
<result property="funurl" column="funurl"/>
</resultMap>
<resultMap type="Function" id="FunctionResultMapWithRelationNestedSelect" extends="FunctionResultMap">
<association property="module" column="mno" select="com.neusoft.busmis.security.dao.IModuleDao.selectByNo"></association>
</resultMap>
<select id="selectListByAll" resultMap="FunctionResultMap">
select * from systemfunction
</select>
<select id="selectListByAllWithNestedSelect" resultMap="FunctionResultMapWithRelationNestedSelect">
select * from systemfunction
</select>
<mapper namespace="com.neusoft.busmis.security.dao.IModuleDao">
<select id="selectByNo" resultType="Module">
select * from systemmodule where mno=#{mno}
</select>
第一个resultmap是没有取关联属性的,type属性写返回的类型,这里写用@Alias注解的信息,id属性表示该resultmap的名字。
然后里面嵌套id和result标签,id表示主键,result表示非主键和非外键,property属性表示model类里的字段,column属性表示映射到数据库里表示的属性。
第二个result马匹是要取出关联属性的,同样要写id和result标签,但这里我们可以用extends属性继承某个resultmap,这样不用重复写。
有两种关联映射:一种是内嵌式select,另一种是内嵌式resultmap。
内嵌式select:
里面嵌套association,property属性表示model类里的关联字段,column属性表示映射到数据库里表示的关联属性,select表示通过关联属性再调用某个select语句,这里要写完整路径。注:各个select标签需在Dao接口提供方法接口。
测试:创建Service接口并实现,这里运用到了session.commit()方法,表示将事务进行提交。JDBC默认是不自动提交事务的,需要手动设置提交,一种就是用commit方法;另一种是在openSession(true)方法里传入true参数,相当于setAutoCommit(true)。
在调用openSession方法时Mybatis会创建SqlSession时同时创建一个Transaction(事务对象),同时autoCommit为false。如果有传入true参数,则autoCommit为true,表示自动提交事务。如果事务失败了,需要在合适的代码里添加session.rollback()回滚事务。
package com.neusoft.busmis.security.service.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.neusoft.busmis.fatory.MyBatisFactory;
import com.neusoft.busmis.security.dao.IFunctionDao;
import com.neusoft.busmis.security.model.FunctionModel;
import com.neusoft.busmis.security.service.IFunctionService;
public class FunctionServiceImpl implements IFunctionService {
@Override
public List<FunctionModel> selectListByAll() throws Exception {
SqlSession session = MyBatisFactory.getSession();
IFunctionDao functionDao = session.getMapper(IFunctionDao.class);
List<FunctionModel> list = functionDao.selectListByAll();
session.commit();
session.close();
return list;
}
@Override
public List<FunctionModel> selectListByAllWithModuleByNestedSelect() throws Exception {
SqlSession session = MyBatisFactory.getSession();
IFunctionDao functionDao = session.getMapper(IFunctionDao.class);
List<FunctionModel> list = functionDao.selectListByAllWithNestedSelect();
session.commit();
session.close();
return list;
}
}
package com.neusoft.busmis.test;
import java.util.List;
import com.neusoft.busmis.security.fatory.ServiceFactory;
import com.neusoft.busmis.security.model.FunctionModel;
import com.neusoft.busmis.security.service.IFunctionService;
public class Test {
public static void main(String[] args) {
IFunctionService fs = ServiceFactory.createFunctionService();
try {
/*
* List<FunctionModel> list = fs.selectListByAll();
for(FunctionModel fm:list) {
System.out.println(fm.getFunname()+"模块名:"+fm.getModule().getMname());
}
*/
List<FunctionModel> list = fs.selectListByAllWithModuleByNestedSelect();
for(FunctionModel fm:list) {
System.out.println(fm.getFunname()+"模块名:"+fm.getModule().getMname());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
selectListByAll()输出,没有取到module管理属性,所以报错
selectListByAllWithModuleByNestedSelect()输出,取到module管理属性,而且每次都得执行一次关联的select语句。有1+N的特性,性能差。
所以使用另一种关联用法--内嵌式resultmap。
在association改为resultmap属性。
<resultMap type="Function" id="FunctionResultMap">
<id property="funno" column="funno"/>
<result property="funname" column="funname"/>
<result property="funurl" column="funurl"/>
</resultMap>
<resultMap type="Function" id="FunctionResultMapWithRelationNestedResultMap" extends="FunctionResultMap">
<association property="module" resultMap="com.neusoft.busmis.security.dao.IModuleDao.ModuleResultMap"></association>
</resultMap>
添加module的resultmap,也是需要全路径 。
<mapper namespace="com.neusoft.busmis.security.dao.IModuleDao">
<resultMap type="Module" id="ModuleResultMap">
<id property="mno" column="mno"/>
<result property="mname" column="mname"/>
</resultMap>
select语句,用inner join内联两张表。
<select id="selectListByAllWithNestedResultMap" resultMap="FunctionResultMapWithRelationNestedResultMap">
select a.*,b.* from systemfunction a inner join systemmodule b on a.mno=b.mno
</select>
测试:service实现类
@Override
public List<FunctionModel> selectListByAllWithModuleByNestedResultMap() throws Exception {
SqlSession session = MyBatisFactory.getSession();
IFunctionDao functionDao = session.getMapper(IFunctionDao.class);
List<FunctionModel> list = functionDao.selectListByAllWithNestedResultMap();
session.commit();
session.close();
return list;
}
main
package com.neusoft.busmis.test;
import java.util.List;
import com.neusoft.busmis.security.fatory.ServiceFactory;
import com.neusoft.busmis.security.model.FunctionModel;
import com.neusoft.busmis.security.service.IFunctionService;
public class Test {
public static void main(String[] args) {
IFunctionService fs = ServiceFactory.createFunctionService();
try {
List<FunctionModel> list = fs.selectListByAllWithModuleByNestedResultMap();
for(FunctionModel fm:list) {
System.out.println(fm.getFunname()+"模块名:"+fm.getModule().getMname());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出,只执行了一条select语句,性能好。
一对多的关联:一对多相对于多对一来的,一个Module表属性对多个Function表属性,
多对多的关联:Module表关联Roles表,User表关联Roles表。
这两个都需要resultMap标签里嵌套collection标签来实现多对多关联。collection和association类似,
<?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="com.neusoft.busmis.security.dao.IModuleDao">
<cache/>
<resultMap type="Module" id="ModuleResultMap">
<id property="mno" column="mno"/>
<result property="mname" column="mname"/>
</resultMap>
<resultMap type="Module" id="ModuleResultMapWithFunctionsByNestedSelect" extends="ModuleResultMap">
<collection property="functions" column="mno" select="com.neusoft.busmis.security.dao.IFunctionDao.selectListByModule"></collection>
</resultMap>
<resultMap type="Module" id="ModuleResultMapWithFunctionsByNestedResultMap" extends="ModuleResultMap">
<collection property="functions" resultMap="com.neusoft.busmis.security.dao.IFunctionDao.FunctionResultMap"></collection>
</resultMap>
<select id="selectListByAll" resultMap="ModuleResultMap">
select * from systemmodule
</select>
<select id="selectListByAllWithFunctionsByNestedSelect" resultMap="ModuleResultMapWithFunctionsByNestedSelect">
select * from systemmodule
</select>
<select id="selectListByAllWithFunctionsByNestedResultMap" resultMap="ModuleResultMapWithFunctionsByNestedResultMap">
select a.*,b.* from systemmodule a inner join systemfunction b on a.mno=b.mno
</select>
<select id="selectByNo" resultMap="ModuleResultMap">
select * from systemmodule where mno=#{mno}
</select>
</mapper>
同理第一个resultmap是没有关联,第二个用内嵌式select,第三个用内嵌式resultmap。然后调用Function的select和resultmap的id。 Function需添加用mno来查询数据,相应的都需要在Dao接口里提供接口方法。
<select id="selectListByModule" resultMap="FunctionResultMap">
select * from systemfunction where mno=#{moduleno}
</select>
在service层实现类调用Dao层方法。测试:
package com.neusoft.busmis.security.service.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.neusoft.busmis.fatory.MyBatisFactory;
import com.neusoft.busmis.security.dao.IModuleDao;
import com.neusoft.busmis.security.model.ModuleModel;
import com.neusoft.busmis.security.service.IModuleService;
public class ModuleServiceImpl implements IModuleService {
@Override
public List<ModuleModel> getselectListByAll() throws Exception {
SqlSession session = MyBatisFactory.getSession();
IModuleDao moduleDao = session.getMapper(IModuleDao.class);
List<ModuleModel> list = moduleDao.selectListByAll();
session.commit();
session.close();
return list;
}
@Override
public List<ModuleModel> getselectListByAllWithFunctionByNestedSelect() throws Exception {
SqlSession session = MyBatisFactory.getSession();
IModuleDao moduleDao = session.getMapper(IModuleDao.class);
List<ModuleModel> list = moduleDao.selectListByAllWithFunctionsByNestedSelect();
session.commit();
session.close();
return list;
}
@Override
public List<ModuleModel> getselectListByAllWithFunctionByNestedResultMap() throws Exception {
SqlSession session = MyBatisFactory.getSession();
IModuleDao moduleDao = session.getMapper(IModuleDao.class);
List<ModuleModel> list = moduleDao.selectListByAllWithFunctionsByNestedResultMap();
session.commit();
session.close();
return list;
}
@Override
public List<ModuleModel> selectListByModule(int moduleNo) throws Exception {
// TODO Auto-generated method stub
return null;
}
}
main
package com.neusoft.busmis.test;
import java.util.List;
import com.neusoft.busmis.security.fatory.ServiceFactory;
import com.neusoft.busmis.security.model.ModuleModel;
import com.neusoft.busmis.security.service.IModuleService;
public class Test {
public static void main(String[] args) {
IModuleService fs = ServiceFactory.createModuleService();
try {
/*List<FunctionModel> list = fs.getselectListByAll();
for(FunctionModel fm:list) {
System.out.println(fm.getFunname()+"模块名:"+fm.getModule().getMname());
}*/
/*List<FunctionModel> list = fs.getselectListByAllWithModuleByNestedResultMap();
for(FunctionModel fm:list) {
System.out.println(fm.getFunname()+"模块名:"+fm.getModule().getMname());
}*/
/*List<ModuleModel> list = fs.getselectListByAllWithFunctionsByNestedSelect();
for(ModuleModel mm:list) {
System.out.println(mm.getMname()+"功能个数:"+mm.getFunctions().size());
}*/
List<ModuleModel> list = fs.getselectListByAllWithFunctionsByNestedResultMap();
for(ModuleModel mm:list) {
System.out.println(mm.getMname()+"功能个数:"+mm.getFunctions().size());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
内嵌式select
内嵌式resultmap
多对多的:Module表关联Roles表,内嵌式select需要在另一张关联表写select语句,注意这里得使用子查询以及in语法来查询数据。而内嵌式resultmap需要写高级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">
<mapper namespace="com.neusoft.busmis.security.dao.IModuleDao">
<cache/>
<resultMap type="Module" id="ModuleResultMap">
<id property="mno" column="mno"/>
<result property="mname" column="mname"/>
</resultMap>
<resultMap type="Module" id="ModuleResultMapWithRolesByNestedSelect" extends="ModuleResultMap">
<collection property="roles" column="mno" select="com.neusoft.busmis.security.dao.IRoleDao.selectListByModule"></collection>
</resultMap>
<resultMap type="Module" id="ModuleResultMapWithRolesByNestedResultMap" extends="ModuleResultMap">
<collection property="roles" resultMap="com.neusoft.busmis.security.dao.IRoleDao.RoleResultMap"></collection>
</resultMap>
<select id="selectListByAll" resultMap="ModuleResultMap">
select * from systemmodule
</select>
<select id="selectListByAllWithRolesByNestedSelect" resultMap="ModuleResultMapWithRolesByNestedSelect">
select * from systemmodule
</select>
<select id="selectListByAllWithRolesByNestedResultMap" resultMap="ModuleResultMapWithRolesByNestedResultMap">
select a.*,c.* from systemmodule a left outer join rolemodule b on a.mno=b.mno
left outer join roles c on b.rno=c.rno
</select>
</mapper>
<?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="com.neusoft.busmis.security.dao.IRoleDao">
<cache/>
<resultMap type="Role" id="RoleResultMap">
<id property="rno" column="rno"/>
<result property="rname" column="rname"/>
</resultMap>
<select id="selectListByModule" resultMap="RoleResultMap">
select * from roles where rno in (select rno from rolemodule where mno=#{moduleNo})
</select>
</mapper>
测试:dao接口以及service就忽略展示了。
通过注解模式编写sql语句
在dao层接口加注解@Select、@Update、@Results
@Results对应@ResultMap,里面嵌套多个@Result注解,有id=true表示<id>标签,没有则表示<result>标签,one表示<association>标签,many表示<collection>标签。
@Mapper
public interface IFunctionDao {
@Insert("insert into systemfunction values (default,#{mno},#{funname},#{funurl})")
public void create(FunctionModel functionModel)throws Exception;
@Results(value = {
@Result(id = true,property = "funno",column = "funno"),
@Result(property = "funname", column = "funname"),
@Result(property = "funurl",column = "funurl"),
@Result(property = "module",column = "mno",one = @One(select = ""))
})
public List<FunctionModel> selectListByAllWithNestedSelect() throws Exception;
}