Mybatis框架总结
作用:数据访问层框架,底层是对JDBC的封装
优点:不需要实现类,只需要写执行的sql语句
环境搭建
- 导入jar包
- src下新建全局配置文件Mybatis.xml,,该文件中主要是对连接数据库的配置,对JDBC的封装。
全局配置文件内容:
<?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.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://localhost:8080/Student"/>
<property name="username" value="sa"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/StudentMybatis.xml"/>
</mappers>
</configuration>
其中:
<transactionManager /> type属性可取值:
JDBC:事务管理使用JDBC原生事务管理方式
MANAGED:将事务管理转交给其他容器
<dataSource />type属性:
POOLED:用数据库连接池
UNPOOLED:和直接使用JDBC一样
JNDI:java命名目录接口
- 在src下新建mapper包,创建实体类名Mapper.xml文件,作用是编写需要执行的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">
<!-- namesapce:理解成实现类的全路径(包名+类名) -->
<mapper namespace="a.b" >
<!-- id:方法名
parameterType:定义参数类型
resultType:返回值类型.
如果方法返回值是list,在resultType中写List的泛型,因为mybatis
对jdbc封装,一行一行读取数据
-->
<select id="selAll" resultType="pojo/Student">
select * from flower
</select>
</mapper>
- 在src下创建事件类的包pojo,并创建实现类文件。
package pojo;
public class Student {
private int snum;
private String sname;
private int sex;
private String sclass;
public Student() {
super();
}
public Student(int snum, String sname, int sex, String sclass) {
super();
this.snum = snum;
this.sname = sname;
this.sex = sex;
this.sclass = sclass;
}
@Override
public String toString() {
return "student [snum=" + snum + ", sname=" + sname + ", sex=" + sex
+ ", sclass=" + sclass + "]";
}
public int getSnum() {
return snum;
}
public void setSnum(int snum) {
this.snum = snum;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getSclass() {
return sclass;
}
public void setSclass(String sclass) {
this.sclass = sclass;
}
}
- 在src下创建service包,创建实现类的接口,并实现接口
package service;
import java.io.IOException;
import java.util.List;
import pojo.PageInfo;
import pojo.Student;
public interface StudentService {
//查看全部信息
List<Student> show() throws IOException;
//对数据进行分页显示,输入每页大小和当前页数
PageInfo showPage(int PageSize,int PageNum) throws IOException;
}
package service;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
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 pojo.PageInfo;
import pojo.Student;
public class StudentServiceImpl implements StudentService{
public List<Student> show() throws IOException{
InputStream is=Resources.getResourceAsStream("Mybatis.xml");
//使用简单工厂类
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
SqlSession session=factory.openSession();
List<Student> list=session.selectList("mapper.StudentMapper.xml");
session.close();
return list;
}
public PageInfo showPage(int PageSize,int PageNum) throws IOException{
//使用工厂设计模式
InputStream is=Resources.getResourceAsStream("Mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
SqlSession session=factory.openSession();
PageInfo pi=new PageInfo();
pi.setPageNum(PageNum);//设定当前页
pi.setPageSize(PageSize);//设定每页数量
Map<String,Object> map=new HashMap();
map.put("PageStart", PageSize*(PageNum-1));//页面初始值
map.put("PageSize", PageSize);
pi.setList(session.selectList("mapper.StudentMapper.xml"));
int count=session.selectOne("mapper.StudentMapper.xml");
pi.setTotol(count%PageSize==0?count/PageSize:count/PageSize+1);
return pi;
}
}
- 子src下创建servlet包,创建servlet。
package servlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import pojo.Student;
import service.StudentService;
import service.StudentServiceImpl;
public class selServlet extends HttpServlet {
private StudentService studentservice=new StudentServiceImpl();
@Override
public void service(HttpServletRequest req,HttpServletResponse res) throws ServletException, IOException{
List<Student> list=studentservice.show();
req.setAttribute("list", list);
req.getRequestDispatcher("index.jsp").forward(req, res);
}
}
- 在src下创建测试包test,并创建Test文件
package 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 pojo.Student;
public class TestStudent {
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> list=session.selectList("a.b.selAll");
for(Student student:list){
System.out.println(student.toString());
}
session.close();
}
}
数据库连接池
在内存中开辟一块空间,存放多个数据库连接对象。存在两个状态:
active:当前连接对象被应用程序使用中。
idle:空闲状态,等待应用程序使用
目的:高频率访问数据库时,使用数据库连接池可以降低服务器系统压力,提高程序运行效率。其中,小型项目不适用数据库连接池。
实现JDBC-Tomcat pool的步骤:
- 在Web项目中的META-IF中存放context.xml,在context.xml中编写数据库连接池属性。
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
url="jdbc:sqlserver://localhost:8080/Student"
username="sa"
password="123456"
maxActive="50"
maxIdle="20"
name="test"
auth="Container"
maxWait="10000"
type="javax.sql.DataSource"
/>
</Context>
-
发布项目到Tomcat上,在java上使用jndi获取数据库连接池中的对象。
context:上下文接口,context.xml:文件对象类型
代码如下:
3 . 当关闭连接对象时,把连接对象归还给数据库连接池,将状态改为idle。
三种查询方式
1.selectList(),返回值为List<resultType 属性控制>
适用于查询结果都需遍历的需求。
List<Flower> list = session.selectList("a.b.selAll");
for (Flower flower : list) {
System.out.println(flower.toString());
}
2.selectOne(),返回Object,适用于返回结果只是变量或一行数据。
int count = session.selectOne("a.b.selById");
System.out.println(count);
3 .selectMap(),返回Map,适用于需要在查询结果中通过某列的值取到这行数据的需求。
//把数据库中哪个列的值当作map的key
Map<Object, Object> map = session.selectMap("a.b.c", "name123");
System.out.println(map);
<settings>
标签
在mybatis全局配置文件中,控制mybatis全局开关
必须保证有log4j.jar
在src下有log4j.properties
<settings>
<setting name="LogImpl" value="LOG4J"/>
</settings>
parameterType属性
- 在mapper.xml中和等标签的parameterType可以控制参数类型
- Sqlession的selectList()和seletOne()的第二个参数和selectMap()的第三个参数都表示方法的参数。
#{}和${}的区别
- #{}获取参数的内容,索引获取,param1获取指定位置参数并且sql使用?占位。
- ${}字符串拼接不使用?,默认找 ${内容}的get/set方法。
Mybatis中实现mysql分页写法
- 在pojo下创建page文件
package com.bjsxt.pojo;
import java.util.List;
public class PageInfo {
//每页显示个数
private int pageSize;
//当前第几页
private int pageNumber;
//总页数
private long total;
//当前页显示的数据
private List<?> list;
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 long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public List<?> getList() {
return list;
}
public void setList(List<?> list) {
this.list = list;
}
}
- 在servlet中创建分页的servlet文件
package 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 pojo.PageInfo;
import service.StudentService;
import service.StudentServiceImpl;
public class PageInfoServlet extends HttpServlet{
private StudentService studentservice=new StudentServiceImpl();
@Override
public void service(HttpServletRequest req,HttpServletResponse res) throws ServletException, IOException{
//第一次访问的验证,当没有传递参数,设置默认值
String PageSizeStr=req.getParameter("PageSize");
int PageSize=2;//初始化页面大小
if(PageSizeStr!=null&&!PageSizeStr.equals(" ")){
PageSize=Integer.parseInt(PageSizeStr);
}
String PageNumStr=req.getParameter("PageNum");
int PageNum=1;//初始化当前页
if(PageNumStr!=null&&!PageNumStr.equals(" ")){
PageNum=Integer.parseInt(PageNumStr);
}
PageInfo pi=studentservice.showPage(PageSize, PageNum);//将页面大小信息和当前页信息传入
req.setAttribute("PageInfo", pi);
req.getRequestDispatcher("index.jsp").forward(req,res);
}
}
mapper.xml文件中添加以下代码:
<select id="selByPage" resultType="Student" parameterType="map">
select * from people limit #{PageStart},#{PageSize}
</select>
Mybatis实现插入
JDBC中的executeupdate()执行新增、删除、修改的sql。返回值int,为受影响的行数。
mybatis中<insert>、<delete>、<update>标签无resultType属性,认为属性值都是int。
-
实现新增
-
在mapper.xml中添加如下代码:
<insert id="ins" parameterType="pojo.Student">
insert into student(snum,sname,sex,sclass) values(#{snum},#{sname},#{sex},#{sclass})
</insert>
- 使用session调用insert()方法
public class Test {
public static void main(String[] args) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = factory.openSession();
// People peo =new People();
// peo.setId(1);
//显示几个
// int pageSize = 2;
//第几页
// int pageNumber = 2;
//如果希望传递多个参数,可以使用对象或map
// Map<String,Object> map = new HashMap<>();
// map.put("pageSize", pageSize);
// map.put("pageStart", pageSize*(pageNumber-1));
// List<People> p = session.selectList("a.b.page",map);
// System.out.println(p);
People p = new People();
p.setName("新增name1");
p.setAge(88);
try {
int index = session.insert("a.b.ins", p);
if(index>0){
System.out.println("成功");
}else{
System.out.println("失败");
}
} catch (Exception e1) {
// e1.printStackTrace();
session.rollback();
}
p.setName("aa");
try {
int index1 = session.insert("a.b.ins", p);
if(index1>0){
System.out.println("成功");
}else{
System.out.println("失败");
}
} catch (Exception e) {
// e.printStackTrace();
session.rollback();
}
session.commit();*/
Mybatis实现删除
- 在mapper.xml中添加如下代码:
<delete id="del" parameterType="pojo.Student">
delete from student whele id=#{0}
</delete>
- 使用session调用delete方法
int del = session.delete("a.b.del",3);
if(del>0){
System.out.println("成功");
}else{
System.out.println("失败");
}
session.commit();
session.close();
System.out.println("程序执行结束");
Mybatis实现更新
- 在Mapper.xml中添加如下代码:
<update id="upd" parameterType="pojo.Student">
update student set snum=#{snum} whele sname=#{sname}
</update>
- 使用session调用update方法:
**
* 实现修改id=3的name=王五
*
* 并输出执行结果
*/
People peo = new People();
peo.setId(4);
peo.setName("王五");
int index = session.update("a.b.upd", peo);
if(index>0){
System.out.println("成功");
}else{
System.out.println("失败");
}
session.commit();
Mybatis接口绑定及多参数传递
- 作用:实现创建一个接口后把mapper.xml由mybatis生成接口的实现类,通过调用接口对象就可以获得mapper.xml的sql语句。
- 实现步骤:
- 在mapper.xml中创建一个接口,包名和接口名为namespace中的值,接口中的方法名和mapper.xml的id属性一样。
- 在mybatis.xml中使用
<package>
进行扫描接口。
多参数实现方法步骤: - 在mybatis.xml中
<mappers>
中使用<package>
<mappers>
<package name="mapper"/>
</mappers>
- 在mapper下新建接口
public interface LogMapper{
List<Log> selAll();
}
- 在mapper.xml中新建LogMapper.xml。namespace必须和接口全限定路径一致,id值必须是和接口中的方法名一致,当接口中方法是多参数,,可省略parameterType
<mapper namespace="com.bjsxt.mapper.LogMapper">
<insert id="ins" parameterType="log">
insert into log values(default,#{accOut},#{accIn},#{money})
</insert>
</mapper>
动态SQL
根据不同的条件需要执行不同的SQL命令。Mybatis中动态SQL在mapper.xml中添加逻辑判断。
- if使用
<select id="selByAccinAccout" resultType="log">
select * from log where 1=1
OGNL表达式,直接写key或对象的属性.不需要添加任何特字符号
<if test="accin!=null and accin!=''">
and accin=#{accin}
</if>
<if test="accout!=null and accout!=''">
and accout=#{accout}
</if>
</select>
- where
如果内容中第一个是and去掉第一个and,如果where中有内容会生成where关键字,如果没有内容不生成where关键字。
<select id="selByAccinAccout" resultType="log">
select * from log
<where>
<if test="accin!=null and accin!=''">
and accin=#{accin}
</if>
<if test="accout!=null and accout!=''">
and accout=#{accout}
</if>
</where>
</select>
- choose、when、otherwise
只要有一个成立,其他都不执行。
<select id="selByAccinAccout" resultType="log">
select * from log
<where>
<choose>
<when test="accin!=null and accin!=''">
and accin=#{accin}
</when>
<when test="accout!=null and accout!=''">
and accout=#{accout}
</when>
</choose>
</where>
</select>
- set用来修改SQL中的set语句。可以去掉最后一个逗号,如果set里面有内容生成set关键字,没有就不生成。
<update id="upd" parameterType="log" >
update log
<set>
id=#{id},
<if test="accIn!=null and accIn!=''">
accin=#{accIn},
</if>
<if test="accOut!=null and accOut!=''">
accout=#{accOut},
</if>
</set>
where id=#{id}
</update>
- Trim
prefix在前面添加内容,prefixOverrides去掉前面内容,suffix在后面添加内容,suffixOverrides去掉后面的内容。
<update id="upd" parameterType="log">
update log
<trim prefix="set" suffixOverrides=",">
a=a,
</trim>
where id=100
</update>
<select id="selByLog" parameterType="log" resultType="log">
select * from log
<trim prefix="abc" prefixOverrides="abc">abc</trim>
</select>
- bind
作用:给参数重新赋值
使用场景:模糊查询,在原内容的前后添加内容
<select id="selByLog" parameterType="log" resultType="log">
<bind name="accin" value="'%'+accin+'%'"/>
#{money}
</select>
- foreach
循环参数内容,在内容前后添加内容,加分隔符。
<select id="selIn" parameterType="list" resultType="log">
select * from log where id in
<foreach collection="list" item="abc" open="(" close=")" separator=",">
#{abc}
</foreach>
</select>
- sql和include
某些sql片段如果希望复用,使用sql定义该片段。
<sql id="mysql">
id,accin,accout,money
</sql>
在select或delete或update或insert中使用include引用。
<select id="">
select <include refid="mysql"></include>
from log
</select>
ThreadLocal
线程容器,给线程绑定一个Object内容,以后只要线程不变,可以随时取出。改变线程无法取出内容。代码如下:
缓存
-
应用程序和数据库交互的过程是一个相对比较耗时的过程。
-
缓存存在的意义:让应用程序减少对数据库的访问,提升程序运行效率。
-
Mybatis中默认sqlSession缓存开启
- 同一个sqlsession对象调用同一个select时,只有第一次访问数据库,之后把查询的结果缓存到sqlsession缓存区中。
- 缓存的是statement对象。在mybatis中一个select对应一个statement对象。有效范围必须是同一个sqlsession对象。
-
缓存流程
- 先到缓存区中找到是否存在statement
- 返回结果
- 如果没有缓存statement对象,去数据库获取数据
- 数据库返回查询结果
- 将查询结果放到对应的缓存区中
-
sqlSessionFactory缓存(二级缓存)
-
范围:同一个factory内每个sqlsession都可以获取
-
使用时间::当数据频繁使用,很少被修改
-
步骤:
- 在mapper.xml中添加,当不写readOnly=“true”需要把实体类序列化
<cache readOnly="true"></cache>
- 在mapper.xml中添加,当不写readOnly=“true”需要把实体类序列化
-
当 SqlSession 对象 close()时或 commit()时会把 SqlSession 缓存 的数据刷(flush)到 SqlSessionFactory 缓存区中。