MyBatis记录(一)

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&amp;useUnicode=true&amp;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写数据库地址,注意&要用&amp;使用;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;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值