Java高级框架——Mybatis学习

北京尚学堂——基于此教育机构的视频所学习

 

目录

壹、什么是框架?

贰、Mybatis

一、mybites简介

二、搭建环境

三、环境搭建的详解

四、三种查询方式

五、注解

六、路径

七、Log4J日志(Log  for  Java)(标签)

八、parameterType类型

完整实现一个数据翻页

九、别名 Typealiases(mybatis设置)

十、Mybatis实现新增(事务处理)

实现一个银行转账(加+数据分页,分页具体步骤已在上面实现)

 

十一、getMapper接口绑定以及多参数传递

十二、动态SQL

十二、ThreadLocal+OpenSessionInView(实现mybatis的封装(利用Filter))

十三、缓存

十四、Mybaits的多表查询

十五、Mybatis的注解

十六、Mybatis的运行原理

班级查询功能

飞机起降系统查询


 

 

对我而言,算是第一次接触框架,框架是是什么,我感觉像是我在以前学习中把一些复用率高的代码封装起来,方便自己的使用或者说别人的使用。对于刚开始接触的我来说,最大的用处就是减少重复劳力。重复造轮子

壹、什么是框架?

  1. 框架:软件的半成品.未解决问题制定的一套约束,在提供功能基础上进行扩充。
  2.  框架中一些不能被封装的代码(变量),需要使用框架者新建一个xml 文件,在文件中添加变量内容.
    1. 需要建立特定位置和特定名称的配置文件
    2. 需要使用XML解析技术和反射技术
  3. 常用概念:
    1. 类库:提供的类没有封装一定的逻辑,
      1. eg:类库就是名言警句,写作文时引入
    2. 框架:里面有一些特定的约束
      1. eg:框架是选择题

 

       eg:我们可以写俩个程序理解下框架

我们先创建俩个项目,MyProject作为正常的项目,Framework作为框架,那我们要如何使用框架里面写的东西呢?

 

贰、Mybatis

一、mybites简介

  • Mybatis 开源免费框架.原名叫iBatis,2010在googlecode,2013年迁移到 github
  • 作用:数据库访问层框架
    • 底层对JDBC封装
  • 优点:不需要编写实现类,只需要写需要的sql命令语句;

二、搭建环境

1. 导入 jar

2. 在 src 下新建全局配置文件(编写 JDBC 四个变量)

  • 没有名字路径要求
  • 在全局配置文件中引入DTD或schema
  • 在全局配置文件中引入 DTD 或 schema

    •  

       如果导入 dtd 后没有提示

      Window-->preference-->Myeclipse->Files and Editors-->XML-->XMlcatalog-->add 按钮

       

 全局配置文件内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
  <!-- 全局配置文件内容 -->
<configuration>
	<!-- default引用的environment的id ,当前所使用的环境 -->
	<environments default="default">
		<!-- 声明可以使用的环境、可以配置多个环境 -->
		<environment id="default">
			<!-- 事务: 使用原生JDBC  -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 利用数据库连接池技术 -->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql://localhost:3306/rejava"/>
				<property name="username" value="root"/>
				<property name="password" value="1327148745"/>
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="com/tk/mapper/StudentMapper.xml"/>
	</mappers>
</configuration>



3. 新建以 mapper 结尾的包,在包下新建:实体类名+Mapper.xml

  • 文件作用:编写需要执行的sql命令
  • 可把xml理解为实现类

XML内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  <!-- namespace理解为实现类的全路径(包名+类名) -->
<mapper namespace="com.tk">
	<!-- id 方法名 
		 paramaterType  参数类型
		 resultType		返回值类型
		 
		 如果返回值的List类型,在resultType中写的List的泛型,因为mybatis
		 对jdbc封装,一行一行读取数据
	-->
	<select id="selAll"  resultType="com.tk.pojo.Student">
		<!-- 利用反射机制自动赋值(auto mapping 自动映射,通过同名),
			但要求属性值要相对一样(数据库中名字和实体类中属性名)
		 -->
		select * from Student
	</select>
</mapper>

4.测试结果(只有在单独使用 mybatis 时使用,最后 ssm 整合时下面代码不需要编写.)

package com.tk.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

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

import com.tk.pojo.Student;

public class Test {
	public static void main(String args[]) throws IOException {
		
		InputStream is = Resources.getResourceAsStream("mybatis.xml");
		//使用工厂设计模式
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
		//生产SqlSession
		SqlSession session = factory.openSession();
		
		List<Student> lists = session.selectList("com.tk.selAll");
		for (Student stu : lists) {
			System.out.println(stu);
		}
		
		session.close();
	}
}

测试结果

Student [id=1, name=田坤, sex=男, age=18]
Student [id=2, name=宋旭东, sex=女, age=18]
Student [id=3, name=宁迁迁, sex=男, age=18]
Student [id=4, name=吴飞龙, sex=男, age=18]

假如,我们的实体类和数据库中的名字不一样,那么通过反射机制还可以赋值成功吗?我们尝试把实体类重的属性值name 改为 noname;

下面是我们的输出结果

Student [id=1, name=null, sex=男, age=18]
Student [id=2, name=null, sex=女, age=18]
Student [id=3, name=null, sex=男, age=18]
Student [id=4, name=null, sex=男, age=18]

因为数据库名字和实体类的属性名字不一样,所以无法给name赋值,而从中我们也可得知,我们查询出来结果我数据的键名是对应于数据库的,额,回归正题,那我们如何可以获取到数据呢,我们应该给取别名来操控

<?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.tk">
	<select id="selAll"  resultType="com.tk.pojo.Student">
              <!--将name取别名为 noname-->
		select id,name noname,sex,age from Student
	</select>
</mapper>

下面是我们的改变mapper后的输出结果:同正常一样

Student [id=1, name=田坤, sex=男, age=18]
Student [id=2, name=宋旭东, sex=女, age=18]
Student [id=3, name=宁迁迁, sex=男, age=18]
Student [id=4, name=吴飞龙, sex=男, age=18]

所以,我们在构建实体类的时候要和数据库中的名字保持一致

 

三、环境搭建的详解

  • 全局配置文件中的内容
    • <transactionManager/> type 数据可取值
      • JDBC:事务管理使用JDBC原生事务管理方式
      • Managed:把数据管理交给其他容器,原生JDBC事务--->setAutoMapping(false);
    • <dataSourse/> type的属性值
      • POOLED:使用的是数据库连接池
      • UNPOOLED:不使用数据库连接池,和直接使用JDBC一样
      • JNDI:java命名目录接口技术

 

四、三种查询方式

  • .selectList()  返回值为 List<resultTyp属性控制>
    • 适用于查询结果都需要遍历的需求
  • selectOne()  返回值  Object
    • 适用于返回结果只是一个变量或者一行数据
  • selectMap()  返回值为  Map  <key , resultType控制>
    • 适用于需要在查询结果中通过某列的值获取到这行数据的需求(eg:电话簿)
package com.tk.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

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

import com.tk.pojo.Student;

public class Test {
	public static void main(String args[]) throws IOException {
		
		InputStream is = Resources.getResourceAsStream("mybatis.xml");
		//使用工厂设计模式
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
		//生产SqlSession
		SqlSession session = factory.openSession();
		//查询一:session.selectList
		System.out.println("查询一:selectList");
		List<Student> lists = session.selectList("com.tk.selAll");
		for (Student stu : lists) {
			System.out.println(stu);
		}
		
		//查询二:session.selectOne
		System.out.println("查询二:selectOne");
		Student stu  = session.selectOne("com.tk.selone");
		System.out.println(stu);
		//查询三:session.selectMap
		System.out.println("查询三:selectMap");
		Map<String, Student> stumap = session.selectMap("com.tk.selmap", "name");
		System.out.println(stumap);
		
		session.close();
	}
}

查询结果

查询一:selectList
Student [id=1, name=田坤, sex=男, age=18]
Student [id=2, name=宋旭东, sex=女, age=18]
Student [id=3, name=宁迁迁, sex=男, age=18]
Student [id=4, name=吴飞龙, sex=男, age=18]
查询二:selectOne
Student [id=2, name=宋旭东, sex=女, age=18]
查询三:selectMap
{田坤=Student [id=1, name=田坤, sex=男, age=18], 吴飞龙=Student [id=4, name=吴飞龙, sex=男, age=18], 宁迁迁=Student [id=3, name=宁迁迁, sex=男, age=18], 宋旭东=Student [id=2, name=宋旭东, sex=女, age=18]}

 

五、注解

  1. 注解存在的意义:简化XML文件的开发
  2. 注解在servlet3.0规范之后大力推广
  3. 注解前面的@XXX,表示引用一个@interface
    1. @interface表示注解声明
  4. 注解也可以有属性,它本质就是一个接口(类)
    1. 每次使用注解都需要到导包
  5. 注解语法:@XXX(属性名=值)
  6. 值的分类
    1. 如果值是基本数据类型或字符串:属性名=值
    2. 如果值是数组类型:属性名={值,值}
      1. 如果只有一个值是可以省略大括号
    3. 如果值是类类型,属性名=@名称
  7. 如果注解只需要一个属性赋值,且这个属性是默认属性,可以省略属性名

六、路径

  1. 编写路径为了告诉编译器如何找到其他资源.
  2. 路径分类
    1.  相对路径: 从当前资源出发找到其他资源的过程

    2. 绝对路径: 从根目录(服务器根目录或项目根目录)出发找到其他资源的过程

      1.  标志: 只要以/开头的都是绝对路径

  3. 绝对路径

    1. 如果是请求转发 / 表示项目根目录(WebRoot)

    2. 其他重定向,<img/> <script/>,<style/>,location.href 等/都表示服务器根目录(tomcat/webapps 文件夹),所以我们需要填写路径的时候需要加上项目名称

  4. 如果客户端请求的控制器,控制器转发到JSP后,jsp中如果使用相对路径,需要按照控制器的路径去寻找其他资源

    1. 保鲜方法就使用绝对路径

注意:浏览器不是直接把有静态资源(scr、href......)东西,直接响应回来,而响应的是一个字符串,而浏览器是去解析这个字符串,每次解析到在去请求服务器,服务器在进行响应

 

七、Log4J日志(Log  for  Java)(<Setting>标签)

在mybatis里面同样也支持日志文件输出,日志文件的输出有利于我们调制程序,了解程序的运行过程和细节详细信息

关于Log4j的详细用法

  1. 由 apache 推出的开源免费日志处理的类库.
  2. 作用:
    1. 在项目中编写 System.out.println();输出到控制台,当项目发布到 tomcat 后,没有控制台(在命令行界面能看见.),不容易观察一些输出结果.

    • log4j 不仅能把内容输出到控制台,还能把内容输出到文件中.便于观察结果 

  3. Log4j的输出级别

    1. fatal(致命错误) > error (错误) > warn (警告) > info(普通信息)>debug(调试信息)

那么?如何在Mybatis中使用呢?————》<Settings>标签

 

  • 在Mybatis全局配置文件中,通过<Settings>标签来控制mybatis全局开关
  • 在mybatis.xml文件中开启log4f
    • src必须用  log4j.properties
    • 必须有log4j.jar
    • <settings>
         <setting name="logImpl" value="LOG4J"/>
      </settings>
      
      

       

  • Log4j中可以输出指定内容的日志(控制某个局部内容日志级别)

    • 命名级别(包级别):<mapper>namespace 属性中除了最后一个类名

      • 例如 namespace=”com.bjsxt.mapper.PeopleMapper” 其中包级别为com.bjsxt.mapper,需要在 log4j.propeties 中

        • 先在总体级别调成 Error 不输出无用信息

        • 在设置某个指定位置级别为 DEBUG

        •  

          
          log4j.rootLogger = error,stdout,D
          
          #only output dao data
          log4j.logger.com.tk.mapper = debug
          
          
          log4j.appender.stdout = org.apache.log4j.ConsoleAppender
          log4j.appender.stdout.Target = System.out
          log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
          log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
          
          log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
          log4j.appender.D.File = log/log.txt
          log4j.appender.D.Append = true
          log4j.appender.D.Threshold = DEBUG 
          log4j.appender.D.layout = org.apache.log4j.PatternLayout
          log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
          
          

           

    • 类级别:

      • 3.2.1namespace 属性值 ,namespace 类名

    • 方法级别

      • 使用 namespace 属性值+标签 id 属性

 

八、parameterType类型

  1. 在XXXMapper.xml中<select><delete>等标签的 parameterType 可以控制参数类型

  2. sqlsession的selectOne() selectList()的第二个参数和selectMap()的第三个参数都表示参数的数

    1. <select id="selAll" resultType="com.tk.pojo.User" parameterType="int">
        	select * from m_user where id = #{0}
      </select>

       

    2. 在 Mapper.xml 中可以通过#{}获取参数

      1. parameterType 控制参数类型

      2. #{}获取参数内容

        1. 使用索引,从 0 开始 #{0}表示第一个参数

        2. 也可以使用#{param1}第一个参数

        3.  如果只有一个参数(基本数据类型或 String),mybatis对#{}里面内容没有要求只要写内容即可.

        4. 如果参数是对象   #{属性名}

        5. 如果参数是 map 写成#{key}

  3. #{ } 和 ${ }的区别
    1. #{}   获取参数的内容支持 索引获取,param1获取指定位置参数,并且 SQL 使用?占位符
    2. ${}  字符串拼接不使用?,默认找${内容}内容的 get/set 方法,如果写数字,就是一个数字
  4. 如果在 xml 文件中出现 “<”,“>”,双引号 等特殊字符时可以使用XML 文件转义标签(XML 自身的)
  5. mybatis 中实现 mysql 分页写法
    1. ? 不允许在关键字前后进行数学运算,需要在代码中计算完成后传递到 mapper.xml 中
    2. mapper中
      1. <select id="selAll" resultType="com.tk.pojo.User" parameterType="map">
          select * from m_user limit #{pageStart},#{pageSize}
        </select>

         

    3. 测试类中
      1. InputStream is = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        		
        //每页显示几个
        int pageSize = 3;
        //第几页
        int pageNumber = 1;
        		
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("pageSize", 3);
        map.put("pageStart", pageSize*(pageNumber-1));
        		
        SqlSession session = factory.openSession();
        		
        List<User> listu = session.selectList("selAll",map);
        
        System.out.println(listu);
        session.close();

         

完整实现一个数据翻页

1。mapper层(Dao层)

        <!-- 设置查询分页 -->
  	<select id="selinfo" resultType="User" parameterType="map">
  		select * from m_user limit #{pageStart},#{pageSize}
  	</select>

        <!-- 查询总的数据量 -->
  	<select id="selAllCount" resultType="int">
  		select count(*) from m_user
  	</select>

2.我们把分页信息封装称为一个类

package com.tk.pojo;

import java.util.List;

public class Page {
	//每页显示个数
	private int pageSize;
	//当前第几页
	private int pageNumber;
	//总页数
	private int totol;
	//在泛型里面填写? 表名什么类型都可以
	//当前显示的数据集合
	private List<?> info;
	public int getPageSize() {
		return pageSize;
	}
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
	public int getPageNumber() {
		return pageNumber;
	}
	public void setPageNumber(int pageNumber) {
		this.pageNumber = pageNumber;
	}
	public int getTotol() {
		return totol;
	}
	public void setTotol(int totol) {
		this.totol = totol;
	}
	public List<?> getInfo() {
		return info;
	}
	public void setInfo(List<?> info) {
		this.info = info;
	}
	@Override
	public String toString() {
		return "Page [pageSize=" + pageSize + ", pageNumber=" + pageNumber
				+ ", totol=" + totol + ", info=" + info + "]";
	}
	public Page(int pageSize, int pageNumber, int totol, List<?> info) {
		super();
		this.pageSize = pageSize;
		this.pageNumber = pageNumber;
		this.totol = totol;
		this.info = info;
	}
	public Page() {
		
	}

}

3。业务层(Service + ServiceImpl)

public Page getInfos(int pageSize, int pageNumber) throws IOException {
		InputStream is =  Resources.getResourceAsStream("mybatis.xml");
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
		SqlSession session = factory.openSession();
		
		Page page = new Page();
		page.setPageNumber(pageNumber);
		page.setPageSize(pageSize);
		int count = session.selectOne("selAllCount");
		
		page.setTotol(count/pageSize==0?count/pageSize:count/pageSize+1);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("pageSize",pageSize);
		map.put("pageStart", pageSize*(pageNumber-1));

		List<User> listu = session.selectList("selinfo",map);
		page.setInfo(listu);
		session.close();
		return page;
	}

4.控制器(servlet)

rotected void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		 int number = 1;
		 int size = 2;
		 String pageStart = req.getParameter("pageNumber");
		 String pageSize = req.getParameter("pageSize");
		 if(pageStart!=null && !pageStart.equals("")){
			 number = Integer.parseInt(pageStart);
		 }
		 if(pageSize!=null && !pageSize.equals("")){
			 size = Integer.parseInt(pageSize);
		 }
		 
		 //获取业务层
		 UserService us = new UserServiceImpl();
		 Page page = us.getInfos(size, number);
		 req.setAttribute("page", page);
		 req.getRequestDispatcher("/page.jsp").forward(req, resp);
		 
	}

5.视图层

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'page.jsp' starting page</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  </head>
  
  <body>
    	<table border="2px">
    		<tr>
    			<td>学号</td>
    			<td>姓名</td>
    			<td>年龄</td>
    		</tr>
    		<c:forEach items="${page.info}" var="user">
    			<tr>
    				<td>${user.id }</td>
    				<td>${user.name }</td>
    				<td>${user.age }</td>
    			</tr>
    		
    		</c:forEach>
    		
    	</table>	
    	<a href="page?pageNumber=${page.pageNumber-1 }&pageSize=${page.pageSize}"  <c:if test="${page.pageNumber<=1 }"> onclick="javascript:return false;" </c:if> >上一页</a>
    	<a href="page?pageNumber=${page.pageNumber+1 }&pageSize=${page.pageSize}"  <c:if test="${page.pageNumber>=page.totol }"> onclick="javascript:return false;" </c:if> >下一页</a>
    	
  </body>
</html>

 

九、别名 Typealiases(mybatis设置)

  1. 系统内置别名:一般是把大写变为小写,本身就小写的在前面加下划线
  2. 给某个类起别名
    1.   	<typeAliases>
        		<typeAlias type="com.tk.pojo.User" alias="ctpu"/>
        	</typeAliases>

       

  3. 直接给某个包下所以类起别名,别名为类名,不区分大小写
    1. <typeAliases>
         <package name="com.tk.pojo"/>
      </typeAliases>
系统内置别名
别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator
  

 

十、Mybatis实现新增(事务处理)

  1. 概念复习
    1. 功能:从应用程序角度出发,软件具有哪些功能.
    2. 业务:完成功能时的逻辑.对应 Service 中一个方法
    3. 事务:从数据库角度出发,完成业务时需要执行的 SQL 集合,统称为一个事务
      1. 事务回滚:如果在一个事务中某个 SQL 执行事务,希望回归到事务的原点,保证数据库数据的完整性.(比如在银行存钱)
  2. 在 mybatis 中默认是关闭了 JDBC 的自动提交功能
    1. 每一个 SqlSession 默认都是不自动提交事务.
    2. session.commit()提交事务.
    3. openSession(true);自动提交  等价于=setAutoCommit(true);
  3. mybatis 底层是对 JDBC 的封装.
    1. JDBC 中 executeUpdate()执行新增,删除,修改的 SQL.返回值 int,表示受影响的行数.
    2. mybatis 中<insert><delete><update>标签没有 resultType 属性,认为返回值都是 int
  4. openSession()时 Mybatis 会创建 SqlSession 时同时创建一个Transaction(事务对象),同时 autoCommit 都为 false
    1. 如果出现异常,应该 session.rollback()回滚事务.
  5. 增删改   insert 、delete、update

实现一个银行转账(加+数据分页,分页具体步骤已在上面实现)

1.mapper(Dap)

<mapper namespace="com.tk.mapper.AccountMapper">
	<!-- 通过用户账号和密码返回对应对象 -->
	<select id="selAccount" resultType="Account" parameterType="Account">
		select * from m_account where id = #{id} and password=#{password}
	</select>
	<!-- 通过用户账号和用户名返回对应对象 -->
	<select id="selAccount2" resultType="Account" parameterType="Account">
		select * from m_account where id = #{id} and name=#{name}
	</select>
	<!-- 根据用户修改账户的余额 -->
	<update id="selAccountBalance"  parameterType="Account">
		update m_account set balance=balance +#{balance} where id=#{id}
	</update>
	
</mapper>

2.实体类(Account -账户类  Log-日志类)

package com.tk.pojo;

public class Account {
	//用户账户
	private int id;
	//用户名
	private String name;
	//用户密码
	private String password;
	//账户余额
	private double balance;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public double getBalance() {
		return balance;
	}
	public void setBalance(double balance) {
		this.balance = balance;
	}
	@Override
	public String toString() {
		return "Account [id=" + id + ", name=" + name + ", password="
				+ password + ", balance=" + balance + "]";
	}
	public Account(int id, String name, String password, double balance) {
		super();
		this.id = id;
		this.name = name;
		this.password = password;
		this.balance = balance;
	}
	public Account() {
		super();
	}
	
	

}
package com.tk.pojo;

import java.sql.Timestamp;

/**
 * 用来记录日志信息的实体类
 * @data :2019-4-9上午9:30:22
 * @author :田坤
 */
public class Log {
	private int id;
	private int accOut;
	private int accIn;
	private double money;
	private Timestamp time;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getAccOut() {
		return accOut;
	}
	public void setAccOut(int accOut) {
		this.accOut = accOut;
	}
	public int getAccIn() {
		return accIn;
	}
	public void setAccIn(int accIn) {
		this.accIn = accIn;
	}
	public double getMoney() {
		return money;
	}
	public void setMoney(double money) {
		this.money = money;
	}
	public Timestamp getTime() {
		return time;
	}
	public void setTime(Timestamp time) {
		this.time = time;
	}
	@Override
	public String toString() {
		return "Log [id=" + id + ", accOut=" + accOut + ", accIn=" + accIn
				+ ", money=" + money + ", time=" + time + "]";
	}
	public Log(int id, int accOut, int accIn, double money, Timestamp time) {
		super();
		this.id = id;
		this.accOut = accOut;
		this.accIn = accIn;
		this.money = money;
		this.time = time;
	}
	public Log() {
		super();
	}


}

3.业务层(service +serviceImpl)

package com.tk.service;

import java.io.IOException;

import com.tk.pojo.Account;
import com.tk.pojo.Page;

public interface AccountService {
	
	int ACCOUNTOUT_INFO_ERROR = 1;
	int ACCOUNTOUT_BALANCE_NOTENOUGH =2;
	int ACCOUNTIN_INFO_ERROR = 3;
	int ACCOUNT_ERROR = 4;
	int OK = 5;
	
	/**
	 * 完成俩个用户之间的转账
	 * @param accOut   转账用户
	 * @param accIn	   收款用户
	 * @return
	 */
	int tranfer(Account accOut,Account accIn) throws IOException;
	
	/**
	 * 查询转账信息,并实现分页
	 * @param pageNumber 当前第几页
	 * @param pageSize	   每页的信息数
	 * @return
	 */
	Page pageInfo(int pageNumber,int pageSize) throws IOException;
}
package com.tk.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.Map;
import java.util.*;

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

import com.tk.pojo.Account;
import com.tk.pojo.Log;
import com.tk.pojo.Page;
import com.tk.service.AccountService;

public class AccountServiceImpl implements AccountService{

	private SqlSession getSqlSession(String config) throws IOException{
		InputStream is = Resources.getResourceAsStream(config);
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
		return factory.openSession();
	}
	
	@Override
	public int tranfer(Account accOut, Account accIn) throws IOException {
		SqlSession  session= getSqlSession("mybatis.xml");
		Account accountOut = session.selectOne("com.tk.mapper.AccountMapper.selAccount",accOut);
		//首先判断转账用户账号和密码是否正确
		if(accountOut!=null){
			//判断转账用户的余额是否足够
			if(accountOut.getBalance() >= accOut.getBalance()){
				//判断收款账号的信息
				Account accountIn = session.selectOne("com.tk.mapper.AccountMapper.selAccount2",accIn);
				if(accountIn != null){
					accountIn.setBalance(accOut.getBalance());
					int index = session.update("com.tk.mapper.AccountMapper.selAccountBalance",accountIn);
					accOut.setBalance(-accOut.getBalance());
					index += session.update("com.tk.mapper.AccountMapper.selAccountBalance",accOut);
					//如何俩次操作都成功
					if(index==2){
						
						//记录转账信息,把信息转入到数据库中
						Log log = new Log();
						log.setTime(new Timestamp(System.currentTimeMillis()));
						log.setAccOut(accOut.getId());
						log.setAccIn(accIn.getId());
						log.setMoney(-accOut.getBalance());
						
						int i = session.insert("com.tk.mapper.LogMapper.insInfo", log);
						if(i>0){
							session.commit();
							session.close();
							return OK;
						}else{
							session.rollback();
							return 0;
						}
	
					}else{
						return ACCOUNT_ERROR;
					}
				}else{
					return ACCOUNTIN_INFO_ERROR;
				}

				
			}else{
				
				return ACCOUNTOUT_BALANCE_NOTENOUGH;
			}
		}else{
			
			return ACCOUNTOUT_INFO_ERROR;
		}
		
	}

	@Override
	public Page pageInfo(int pageNumber, int pageSize) throws IOException {
		SqlSession session = getSqlSession("mybatis.xml");
		Page page = new Page();
		page.setPageSize(pageSize);
		page.setPageNumber(pageNumber);
		//查询出信息总数
		int allInfo = session.selectOne("com.tk.mapper.LogMapper.selAll");
		page.setTotal(allInfo/pageSize == 0? allInfo/pageSize : allInfo/pageSize+1);
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("pageStart", (pageNumber-1)*pageSize);
		map.put("pageSize", pageSize);
		List<Log> listl = session.selectList("com.tk.mapper.LogMapper.selPageInfo", map);
		page.setList(listl);
		System.out.println(listl);
		return page; 
	}

}

4.Controller层

package com.tk.servlet;


import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.tk.pojo.Account;
import com.tk.service.AccountService;
import com.tk.service.impl.AccountServiceImpl;

public class transfer extends HttpServlet {
	 @Override
	protected void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		//转账账户
		Account accOut = new Account();
		//收款账户
		Account accIn = new Account();
		if(!req.getParameter("accOutId").equals("")){
			accOut.setId(Integer.parseInt(req.getParameter("accOutId")));
		}
		accOut.setPassword(req.getParameter("accOutPassword"));
		if(!req.getParameter("accOutBalance").equals("")){
			accOut.setBalance(Double.valueOf(req.getParameter("accOutBalance")));
		}
		if(!req.getParameter("accInId").equals("")){
			accIn.setId(Integer.parseInt(req.getParameter("accInId")));
		}
		accIn.setName(req.getParameter("accInName"));
		
		System.out.println(accOut);
		System.out.println(accIn);
		
		AccountService as = new AccountServiceImpl();
		int flag = as.tranfer(accOut, accIn);
		if(flag == 5){
			resp.sendRedirect("/Bank/pageFen");
		}else{
			HttpSession hs = req.getSession();
			hs.setAttribute("code", flag);
			resp.sendRedirect("/Bank/error.jsp");
		}
	}
}

5.视图层

    <form action="transfer">
    	转账账户:<input type="text" name = "accOutId"><br>
    	密码:<input type="password" name = "accOutPassword"><br>
    	转账金额:<input type="text" name = "accOutBalance"><br>
    	收帐账户:<input type="text" name = "accInId"><br>
    	收账用户名:<input type="text" name = "accInName"><br>
    	<input type="submit" value="转账">
    </form>

 

十一、getMapper接口绑定以及多参数传递

1、作用:实现创建一个接口后把mapper.xml由mybatis生成接口的实现类,通过调用接口对象就可以获取 mapper.xml 中编写的 sql.

2、后面 mybatis 和 spring 整合时使用的是这个方案.。、

3、实现步骤

  • 创建一个借口
    • 接口包名和接口名与 mapper.xml 中<mapper>namespace相同

    • 接口中方法名和 mapper.xml 标签的 id 属性相
  • 在 mybatis.xml 中使用<package>进行扫描接口和 mapper.xml

4、代码实现步骤

  • 在 mybatis.xml 中<mappers>下使用<package>
    • 	<mappers>
      		<package name="com.tk.mapper"/>
      	</mappers>
  • 在 com.bjsxt.mapper 下新建接口

    • public interface LogMapper {
      
      	/**
      	 * 查询所有的转账日志信息
      	 * @return
      	 */
      	List<Log> selAll();
      	/**
      	 * 查询俩个用户之前的转账信息
      	 * @param accOut
      	 * @param accIn
      	 * @return
      	 */
      	List<Log> selAccount(int accOut,int accIn);
      	
      }

       

  • 在 com.bjsxt.mapper 新建一个 LogMapper.xml

    • namespace 必须和接口全限定路径(包名+类名)一致

    • id 值必须和接口中方法名相同

    •  如果接口中方法为多个参数,可以省略 parameterType

    •     <mapper namespace="com.tk.mapper.LogMapper">
        	<select id="selAll" resultType="Log">
        		select * from m_log
        	</select> 
        	<!-- 多参数可以不用写参数类型 -->
        	<select id="selAccount" resultType="Log">
        		select * from m_log where accOut=#{0} and accIn=#{1}
        	</select>
         </mapper>

       

5、参数实现方法:

  • 在接口中声明方法
  • 在mapper.xml中添加 #{ 0 / param1 }

6、使用注解方式

  • 在接口中声明方法
    •         /**
      	 * mybatis 把参数转换为 map 了,其中@Param("key") 参数内 容就是 map 的 value 
      	 * @param accOut
      	 * @param accIn
      	 * @return
      	 */
      	List<Log> selAccount(@Param("accOut")int accOut,@Param("accIn") int accIn);

       

  • 在 mapper.xml 中添加 #{ } 里面写@Param(“内容”)参数中内容

    •   	<select id="selAccount" resultType="Log">
        		select * from m_log where accOut=#{accOut} and accIn=#{accIn}
        	</select>

       

十二、动态SQL

1、根据不同的条件需要执行不同的 SQL 命令.称为动态 SQL

2、MyBatis 中动态 SQL 在 mapper.xml 中添加逻辑判断等.

3、if

<select id="selInfoByOutIn" resultType="Log">
  	select * from m_log where 1=1
  	<if test="accOut!=null and accOut!=''">
  	     and accOut=#{accOut}
  	</if>
  	<if test="accIn!=null and accIn!=''">
             and accIn=#{accIn}
  	</if>
 </select>

4、where

  • 当编写 where 标签时,如果内容中第一个是 and 去掉第一个and
  • 如果<where>中有内容会生成 where 关键字,如果没有内容不生成 where 关键
    •  比直接使用<if>少写 where1=1
<select id="selInfoByOutIn" resultType="Log">
  	select * from m_log 
  	<where>
  	    <if test="accOut!=null and accOut!=''">
  		and accOut=#{accOut}
  		</if>
  		<if test="accIn!=null and accIn!=''">
  		       	and accIn=#{accIn}
  		</if>
  	</where>
</select>

5、 choose、when、otherwise

  • 只有有一个成立,其他都不执行。
  • 如果 accIn 和 accOut 都不是 null 或不是””生成的sql 中只有 where accin=?
  <select id="selInfoByOutIn" resultType="Log">
  	select * from m_log 
  	<where>
  	    <choose>
	  	<when test="accOut!=null and accOut!=''">
	  		and accOut=#{accOut}
	  	</when>
	  	<when test="accIn!=null and accIn!=''">
	  		and accIn=#{accIn}
	  	</when>
	  	<otherwise>
	  					
	  	</otherwise>
  	    </choose>
      </where>
 </select>

6、 set

  • 用于修改set中的set从句
  • 作用:去掉最后一个逗号、
  • 如果<set>里面有内容生成 set 关键字,没有就不生成
    • id=#{id} 目的防止<set>中没有内容,mybatis 不生成 set 关键字,如果修改中没有 set 从句 SQL 语法错误.
  <update id="upd">
  	update m_log
  	<set>
  		id=#{id}
  	</set>
  	<if test="accOut!=null and accOut!=''">
  	     ,accOut=#{accOut}
  	</if>
  	<if test="accIn!=null and accIn!=''">
  		,accIn=#{accIn}
  	</if>
  	where id=#{id}
  </update>

 

7、Tirm

  • prefix 在前面添加内容
  • prefixOverrides 去掉前面内容
  • suffix 在后面添加内容
  • suffixOverrieds 去掉后面内容
  • 执行顺序去掉内容后添加内容
      <update id="upd">
      	update m_log
      	<trim prefix="set" suffixOverrides=",">
      		a=a,
      	</trim>
      	where id =100
      </update>

     

8、bind

1、作用:给参数重新赋值

2、应用场景:

  • 模糊查询
  • 在原内容前后添加东西
  <select id="selInfoByOutIn1" resultType="Log">
  	<bind name="money" value="'%'+money+'%'"/>
  	select * from m_log where money like #{money}
  </select>

9、foreach

  • 循环参数内容,还具备在内容的前后添加内容,还具备添加分隔符功能
  • 适用场景:in 查询中.批量新增中(mybatis 中 foreach 效率比较低)
  • 使用:
    • collectino=”” 要遍历的集合
    • item 迭代变量,#{迭代变量名}获取内容
    • open 循环后左侧添加的内容
    • close 循环后右侧添加的内容
    • separator 每次循环时,元素之间的分隔符
  <select id="selInfoByOutIn1" resultType="Log" parameterType="list">
  	select * from m_log where id in 
  	<foreach collection="list" item="aaa" open="(" close=")" separator=",">
  	    #{aaa}
  	</foreach>
  </select>

10、sql  include

1.某些 SQL 片段如果希望复用,可以使用<sql>定义这个片段

  <sql id="mysql">
  	id,accOut,accIn
  </sql>

2.在<select>或<delete>或<update>或<insert>中使用<include>引用

   <select id="selInfoByOutIn2" resultType="Log" parameterType="list">
  	select
  	<include refid="mysql"/>
  	from m_log
  </select>

 

十二、ThreadLocal+OpenSessionInView(实现mybatis的封装(利用Filter))

1.ThreadLocal

 线程容器,给线程绑定一个 Object 内容,后只要线程不变,可以随时取出.

 改变线程,无法取出内容.

            封装mybatis

package com.tk.test;

import java.io.IOException;
import java.io.InputStream;

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

/**
 * Mybatis工具类
 * @data :2019-4-9下午7:06:52
 * @author :田坤
 */
public class MybatisUtil {
    //factory实例化过程是一个比较消耗性能的过程
    //保证有且仅有一个factory
    private static SqlSessionFactory factory = null;
    private static ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();
	//当执行类的时候加载
	static{
		try {
			InputStream is = Resources.getResourceAsStream("mybatis.xml");
			factory = new SqlSessionFactoryBuilder().build(is);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取sqlsession
	 * @return
	 */
	public static SqlSession getSession(){
		SqlSession session = tl.get();
		if(session==null){
			tl.set(factory.openSession());
		}
		return tl.get();
	}
	
	public static void cloesSqlSession(){
		SqlSession session = tl.get();
		if(session!=null){
			session.close();
		}
		tl.set(null);
	}
	
}

            写过滤器(OpenSessionInView)

package com.tk.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

import org.apache.ibatis.session.SqlSession;

import com.tk.test.MybatisUtil;
/**
 * openSessionInView最早是由spring框架提出的,整合hibenate就是用的OpenSessionInView
 * @data :2019-4-9下午7:13:52
 * @author :田坤
 */
//@WebFilter("/*")
public class OpenSessionInView implements javax.servlet.Filter{

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain chain) throws IOException, ServletException {
		SqlSession session = MybatisUtil.getSession();
		try {
			System.out.println("我被执行了");
			chain.doFilter(arg0, arg1);
			session.commit();
		} catch (Exception e) {
			session.rollback();
			e.printStackTrace();
		}finally{
			MybatisUtil.cloesSqlSession();
		}
		
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		System.out.println("过滤器生成了");
		
	}

}

在servlet类中检测

package com.tk.servlet;


import java.io.IOException;
import java.sql.Timestamp;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.ibatis.session.SqlSession;

import com.tk.mapper.LogMapper;
import com.tk.pojo.Log;
import com.tk.test.MybatisUtil;

public class Test extends HttpServlet {
	@Override
	protected void service(HttpServletRequest arg0, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.setContentType("text/html;charset=utf-8");
		SqlSession session = MybatisUtil.getSession();
		LogMapper mapper = session.getMapper(LogMapper.class);
		int i = mapper.ins(new Log(0, "11", "12", 180, new Timestamp(System.currentTimeMillis())));
		resp.getWriter().write(i);
	}
}

十三、缓存

1、应用程序和数据库交互的过程是一个相对比较耗时的过程

2、缓存存在的意义:让应用程序减少对数据库的访问,提升程序运行效率

3、MyBatis 中默认 SqlSession 缓存开启

  •  同一个 SqlSession 对象调用同一个<select>时,只有第一次访问数据库,第一次之后把查询结果缓存到 SqlSession 缓存区(内存)

  • 缓存的是 statement 对象.(简单记忆必须是用一个<select>)

    • 在 myabtis 时一个<select>对应一个 statement 对象

  • 有效范围必须是同一个 SqlSession 对象

4、缓存流程

  1. 步骤一: 先去缓存区中找是否存在 statement
  2. 步骤二:返回结果
  3. 步骤三:如果没有缓存 statement 对象,去数据库获取数据
  4. 步骤四:数据库返回查询结果
  5. 步骤五:把查询结果放到对应的缓存区中

5、SqlSessionFactory缓存

  • 又叫:二级缓存
  • 有效范围:同一个 factory 内哪个 SqlSession 都可以获取
  • 什么时候使用二级缓存:
    • 当数据频繁被使用,很少被修改
  • 使用二级缓存步骤
    • 在 mapper.xml 中添加
      • <cache readOnly="true"></cache>
    • 如果不写 readOnly=”true”需要把实体类序列化
  • 当 SqlSession 对象 close()时或 commit()时会把 SqlSession 缓存的数据刷(flush)到 SqlSessionFactory 缓存区中

 

 

十四、Mybaits的多表查询

 

  1. Mybatis 实现多表查询方式
    1. 业务装配.对两个表编写单表查询语句,在业务(Service)把查询的两个结果进行关联.
    2. 使用AutoMapping特性,在实现两表联合查询时通过别名完成映射
    3. 使用 MyBatis 的resultMap 属性进行实现
  2. 多表查询时,类中包含另一个类的对象的分类
    1. 单个对象
    2. 集合对象

①、ResultMap属性

  1. resultMap 属性写在mapper.xml中,由程序员控制SQL查询结果与实体类的映射关系
    1. 默认 MyBatis 使用 AutoMapping 特性
  2. 使用<resultMap>标签时,<select>标签不写 resultType 属性,而是使用 resultMap 属性引用<resultMap>标签
  3. 使用 resultMap 实现单表映射关系
    1. <resultMap type="Teacher" id="my1">
      	<!-- 主键使用id配置映射关系 -->
      	<id property="id" column="id"/>
      	<!-- 其他列使用result标签配置映射关系 -->
      	<result property="name" column="name"/>
      </resultMap>
      <select id="selAll" resultMap="my1">
      	select * from t_teacher
      </select>
      

       

  4. 使用 resultMap 实现关联单个对象(N+1 方式)

    1. N+1 查询方式,先查询出某个表的全部信息,根据这个表的信息查询另一个表的信息.

    2. 与业务装配的区别:

      1. 在 service 里面写的代码,由 mybatis 完成装配

    3. 实现步骤:

      1. 在 Student 实现类中包含了一个 Teacher 对象

        1. public class Student {
          
          	private int id;
          	private String name;
          	private int age;
          	private int tid;
          	private Teacher teacher;

           

      2. 在 TeacherMapper 中提供一个查询

        1. <select id="selById" resultType="Teacher" parameterType="int">
          	select * from t_teacher where id=#{0}
          </select>

           

      3.  在 StudentMapper 中

        1. <association> 装配一个对象时使用

        2. property: 对象在类中的属性名

        3. select:通过哪个查询查询出这个对象的信息

        4. column: 把当前表的哪个列的值做为参数传递给另一个查询

        5. 大前提使用 N+1 方式.和时如果列名属性名相同可以不配置,使用 Automapping 特性.但是 mybatis 默认只会给列
          专配一次

          1. <resultMap type="Student" id="my1">
            	<id property="id" column="id"/>
            	<result property="name" column="name"/>
            	<result property="age" column="age"/>
            	<result property="tid" column="tid"/>
            	<association property="teacher" select="tk.selById" column="tid"></association>
            </resultMap>
            <select id="selAll" resultMap="my1">
            	select * from t_student
            </select>

             

        6. 把上面代码可以简化为

          1. <resultMap type="Student" id="my1">
            	<result property="tid" column="tid"/>
            	<association property="teacher" select="tk.selById" column="tid"></association>
            </resultMap>
            <select id="selAll" resultMap="my1">
            	select * from t_student
            </select>

             

  5. 使用 resultMap 实现关联单个对象(联合查询方式)

    1. 只需要编写一个 SQL,在 StudentMapper 中添加下面效果

      1. <association/>只要专配一个对象就用这个标签

      2. 此时时把<association/>小的<resultMap>看待

      3. javaType 属性:<association/>专配完后返回一个什么类型的对象.取值是一个类(或类的别名)

      4. <resultMap type="Student" id="stuMap1"> 
        	<id column="sid" property="id"/> 
        	<result column="sname" property="name"/> 
        	<result column="age" property="age"/> 
        	<result column="tid" property="tid"/> 
        	<association property="teacher" javaType="Teacher">
        			<id column="tid" property="id"/> 
        		<result column="tname" property="name"/> 
        	 </association>
         </resultMap> 
        <select id="selAll1" resultMap="stuMap1"> 
        		select s.id sid,s.name sname,age age,t.id tid,t.name tname FROM t_student s left outer join t_teacher t on s.tid=t.id 
        </select>

         

  6.  N+1 方式和联合查询方式对比

    1. N+1:需求不确定时.

    2. 联合查询:需求中确定查询时两个表一定都查询.

  7. N+1 名称由来

    1. 举例:学生中有 3 条数据

    2. 需求:查询所有学生信息级授课老师信息

    3. 需要执行的 SQL 命令

      1. 查询全部学生信息:select*from 学生

      2. 执行 3 遍 select*from 老师 whereid=学生的外键

    4. 使用多条 SQl 命令查询两表数据时,如果希望把需要的数据都查询出来,需要执行 N+1 条 SQl 才能把所有数据库查询出来

    5. 缺点:效率低
    6. 优点:
      1. 如果有的时候不需要查询学生是同时查询老师.只需要执行一个 select*fromstudent
    7. 适用场景: 有的时候需要查询学生同时查询老师,有的时候只需要查询学生
    8. 如果解决 N+1 查询带来的效率低的问题
      1. 默认带的前提: 每次都是两个都查询
      2. 使用两表联合查询

 

②、使用<resultMap>查询关联集合对象(N+1)

  1. 在 Teacher 中添加 List<Student>
    1. public class Teacher {
      	
      	private int id;
      	private String name;
      	private List<?> student;

       

  2. 在 StudentMapper.xml 中添加通过 tid 查询
    1. <select id="selById" resultType="Student" parameterType="int">
      	select * from t_student where tid=#{0}
      </select>

       

  3. 在 TeacherMapper.xml 中添加查询全部
    1. <collection/> 当属性是集合类型时使用的标签.
    2. <resultMap type="Teacher" id="my2">
      	<id property="id" column="id"/>
      	<result property="name" column="name"/>
      	<collection property="student" select="com.tk.mapper.StudentMapper.selById" column="id"></collection>
      </resultMap>
      <select id="selAll2" resultMap="my2">
      	select * from t_teacher 
      </select>

       

③.使用<resultMap>实现加载集合数据(联 合查询方式)

 

  1. 在 teacherMapper.xml 中添加
    1. mybatis 可以通过主键判断对象是否被加载过.
    2. 不需要担心创建重复 Teacher
<resultMap type="Teacher" id="my3">
	<id property="id" column="tid"/>
	<result property="name" column="tname"/>
	<collection property="student" ofType="Student">
		<id property="id" column="sid"/>
		<result property="name" column="sname"/>
		<result property="age" column="age"/>
		<result property="tid" column="tid"/>
	</collection>
</resultMap>
<select id="selAll3" resultMap="my3">
	select t.id teid,t.name tname,s.id sid,s.name sname,age,tid from t_teacher t LEFT JOIN t_student s ON  t.id=s.tid 
</select>

 

④使用 AutoMapping 结合别名实现多表查询

  1. 只能使用多表联合查询方式
  2. 要求:查询出的列别和属性名相同.
  3. 实现方式
    1. 在 SQL 是关键字符,两侧添加反单引号
	<select id="selAll4" resultType="teacher">
		select t.id id,t.name name,s.id `t_student.id` ,s.name `t_student.name`,age,tid  
		from t_teacher t LEFT JOIN t_student s ON  t.id=s.tid 
	</select>

 

十五、Mybatis的注解

1、注解:为了简化配置文件.
2、Mybatis 的注解简化 mapper.xml 文件.  如果涉及动态 SQL 依然使用 mapper.xml

3、mapper.xml和注解可以共存

4、使用注解时 mybatis.xml 中<mappers>使用

  • <package>
  • <mapper class="接口">

5、实现查询

@select("select * from t_student")
List<Student> selAll();

6、实现新增

	@Insert("insert into t_student values(default,#{name},#{age},#{tid})")
	int insertStudent(Student stu);

7、实现修改

	@Update("update t_student set name=#{name} where id = #{id}")
	int updateStudent(Student stu);

8、实现删除

	@Delete("delete from t_student where id =#{0}")
	int deleteStudent(int i);

9、使用注解实现<resultMap>功能

以N+1为例子

@Results() 相当于<resultMap>

@Result() 相当于<id/>或<result/>     

@Result(id=true) 相当与<id/>

@Many() 相当于<collection/>

@One() 相当于<association/>

学生接口

	@Select("select * from t_student where tid=#{0}")
	List<Student> selAll(int i);

教师接口

	@Results(value={
		@Result(id=true,property="id",column="id"),
		@Result(property="name",column="name"),
		@Result(property="list",column="id",many=@Many(select="com.tk.mapper.StudentMapper.selAll"))
			
	})
	@Select("select * from t_teacher")
	List<Teacher> selAll();

 

十六、Mybatis的运行原理

1、运行过程中设计到的类

  • ResourcesMyBatis 中 IO 流的工具类      加载配置文件
  • SqlSessionFactoryBuilder()构建器
    • 作用:创建 SqlSessionFactory 接口的实现类
  • XMLConfigBuilder MyBatis 全局配置文件内容构建器类
    • 作用:负责读取流内容并转换为 JAVA 代码.
  • Configuration 封装了全局配置文件所有配置信息
    • 全局配置文件内容存放在 Configuration 中
  • DefaultSqlSessionFactory 是SqlSessionFactory接口的实现类
  • transaction事务类
    • 每一个 SqlSession 会带有一个 Transaction 对象
  • TransactionFactory 事务工厂
    • 负责生产 Transaction
  • Executor MyBatis 执行器
    • 作用:负责执行 SQL 命令
    • 相当于 JDBC 中 statement 对象(或 PreparedStatement或 CallableStatement)
    • 默认的执行器 SimpleExcutor
    • 批量操作 BatchExcutor
    • 通过 openSession(参数控制)
  • DefaultSqlSession 是 SqlSession 接口的实现类
  • ExceptionFactory   MyBatis 中异常工厂

2、流程图

3、文字解释

在 MyBatis 运行开始时需要先通过 Resources 加载全局配置文件.下面需要实例化 SqlSessionFactoryBuilder 构建器.帮SqlSessionFactory 接口实现类 DefaultSqlSessionFactory.在实例化 DefaultSqlSessionFactory 之前需要先创建 XmlConfigBuilder解析全局配置文件流,并把解析结果存放在 Configuration 中.之后把Configuratin 传递给 DefaultSqlSessionFactory.到此 SqlSessionFactory 工厂创建成功.

由 SqlSessionFactory 工厂创建 SqlSession.每次创建 SqlSession 时,都需要由 TransactionFactory 创建 Transaction对象,同时还需要创建SqlSession 的执行器 Excutor,最后实例化DefaultSqlSession,传递给 SqlSession 接口.根据项目需求使用 SqlSession 接口中的 API 完成具体的事务操作.

如果事务执行失败,需要进行 rollback 回滚事务.
           如果事务执行成功提交给数据库.关闭 SqlSession
 

 

 

班级查询功能

飞机起降系统查询

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值