数据持久层框架Mybatis

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_1018944104/article/details/83301439

目录

1.软件开发3层架构

2.什么是框架?

3.传统JDBC开发的不足?

4.什么是Mybatis?

5.Mybatis入门案例?

6.Mybatis增删改查案例?

7.Mybatis代理实现DAO开发?

8.Mybatis高级映射


1.软件开发3层架构

 软件开发的3层架构是Java提出分层开发(经典开发)模式,即将软件开发分为表示层、业务逻辑层、数据持久层开发,互相独立,各不影响。

表示层

  1. 由与用户进行交互的组件和容器构成(接收请求并响应请求),比如servlet。
  2. 分包:action/web/servlet。
  3. 处理表示层的框架SprintMVC/Struts2。

业务逻辑层

  1. 由业务处理的组件组成。
  2. 分包:service/biz。
  3. 处理业务逻辑层的框架Spring Framwork。

数据持久层

  1. 实现与数据库直接交互,比如jdbc。
  2. 分包:dao。
  3. 处理数据持久层的框架Mybatis/Hibernate/JdbcTemplate。

2.什么是框架?

定义

  1. 将重复性的、繁琐的内容封装起来的一套程序。
  2. 框架使开发人员能够将更多地精力放在业务的分析和理解上。

好处

  1. 简化开发,配置即可
  2. 屏蔽细节
  3. 提高开发效率

3.传统JDBC开发的不足?

在引入框架之前,我们都使用JDBC完成数据持久层的开发,但有下面几处不足:

  1. 数据库驱动注册和连接获取的硬编码问题(配置文件解决)
  2. SQL预编译时赋值和结果集封装的时候繁琐(反射解决 ORM,即对象关系映射)
  3. 频繁打开和释放连接消耗资源(连接池解决)

4.什么是Mybatis?

官网http://www.mybatis.org/mybatis-3

  1. MyBatis 是一款优秀的持久层框架
  2. MyBatis只需要关注SQL语句、输入参数和输出结果的映射
  3. MyBatis是一个ORM框架。ORM表示对象关系映射,解决面向对象编程模型和关系型数据库模型之间的映射问题。

5.Mybatis入门案例?

步骤

  1. 准备jar包,mysql驱动包(mysql-connector-java-5.1.45-bin.jar)和Mybatis核心jar包(mybatis-3.4.5.jar)
    1. Mybatis原本是apache项目,原来被叫做 ibatis
    2. 后来移植到google code,改名为mybatis
    3. 现在在github(开源软件托管平台)脱光,官网:https://github.com/mybatis/mybatis-3/releases
  2. 创建Java项目,并将前面的2个jar包导入项目,如下图所示,其中lib目录手动创建,2个jar拷贝到lib,并build path二者。
  3. 创建并编写2种配置文件
    1. 全局配置文件:4个参数配置连接池、进行事务管理
    2. 映射配置:定制化sql语句、输入参数与输出结果映射
    3. 配置方式:
      1. 在Java项目下创建source folder(与src目录同级并且一样的目录)用于存放配置文件
      2. 全局配置文件和映射配置文件的编写方式见下方代码
  4. 读取配置并运行测试
    1. Sqlsession:面向开发者的一个接口,提供了发送sql命令的方法。
    2. SqlSessionFactory:session工厂,创建和管理session对象的。

代码

项目目录结构

pojo中User类

package pojo;
public class User {
	private int uid;
	private String uname;
	private String password;
	public int getUid() {
		return uid;
	}
	public void setUid(int uid) {
		this.uid = uid;
	}
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	@Override
	public String toString() {
		return "User [uid=" + uid + ", " + (uname != null ? "uname=" + uname + ", " : "") + (password != null ? "password=" + password : "") + "]";
	}
}

Java属性文件jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///bd1808?useSSL=true
user=root
password=root

全局配置文件mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 这段主要作用就是约束当前文档怎么去写
	xml描述文件:dtd/schema,作用是约束标签
 -->
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <!-- 加载外部属性文件 -->	
  <properties resource="jdbc.properties"></properties>
  <!-- 类型别名:标签时候顺序的,这个必须写到properties标签的后面 -->
  <typeAliases>
 	<!-- 单个类型别名 -->
  	<!-- <typeAlias alias="user" type="pojo.User"/> -->
  	<!-- 批量起别名:别名就是类名,而且不区分大小写 -->
  	<package name="pojo" />
  </typeAliases>
  <!-- 环境context:复数 
  	mysql、oracle、db2
  	本地环境、预上线环境、线上环境
  	default:默认使用环境
  -->
  <environments default="development">
  	<!-- 环境:id是唯一表示 -->
    <environment id="development">
      <!-- 事务管理器:JDBC,mybatis框架的事务管理器 -->
      <transactionManager type="JDBC"/>
      <!-- 数据源:POOLED连接池(存储连接) 其他连接池:dbcp/c3p0/druid/jdbctemplate -->
      <dataSource type="POOLED">
      	<!-- name属性的值都是固定的,必须这么写,否则框架无法识别 -->
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${user}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 映射器 :配置映射文件路径-->
  <mappers>
    <mapper resource="UserMapper.xml"/>
  </mappers>
</configuration>

 映射配置文件UserMapper.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:命名空间(字符串)
	隔离sql
	这里abcd随便写的
	 -->  
<mapper namespace="ahsb1">
  <!-- 
  	根据uid查询user的对象
  	一个标签就代表一个Statement的对象
  	#{}:代表占位符,在jdbc里面就是?的意思
  	#{}中的id:关键字,即输入参数
  		参数是简单类型:比如基本数据类型和字符串,可任意
  		参数是用类型:属性名称
  	id:标签的唯一表示
  	parameterType:输入参数类型(可选),不写就会进行类型推断
  	resultType:	输出结果类型(单个结果的类型)
   -->
  <select id="selectUser" resultType="User">
    select * from user where uid = #{uid}
  </select>
  <!-- 查询所有 -->
  <select id="selectAll" resultType="User">
  	select * from user
  </select>
  <!-- 模糊查询
  	${}:表示连接
  		关键字与输入参数的类型有关:
  			简单类型:value
  			引用类型:属性名称
   -->
  <select id="selectLikeName" resultType="User">
  	select * from user where uname like '%${value}%'
  </select>
  <!-- 插入 -->
  <insert id="insert1" >
  	insert into user(uname,password) values(#{uname},#{password})
  </insert>  
</mapper>

测试类Test

package test;
import java.io.IOException;
import java.io.Reader;
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.User;
public class Test {
	public static void main(String[] args) throws IOException {
		//读取配置文件
		Reader reader = Resources.getResourceAsReader("mybatis.xml");
		SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
		//发送定制好的sql
		//SqlSession session = ssf.openSession();//关闭自动提交
		SqlSession session = ssf.openSession(true);//不关闭自动提交
		/*User user = session.selectOne("ahsb.selectUser", 1);
		System.out.println(user);*/
		//查询所有
		/*List<User> users = session.selectList("ahsb.selectAll");
		System.out.println(users);*/
		//模糊查询
		/*List<User> users = session.selectList("ahsb.selectLikeName","s");
		System.out.println(users);*/
		User user = new User();
		user.setUname("zl");
		user.setPassword("123");
		int rows = session.insert("ahsb1.insert1", user);
		//手动事务提交
		//session.commit();
		System.out.println(rows);
		session.close();
	}
}

6.Mybatis增删改查案例?

参见上面第5部分的代码,注意点如下:

  1. 查询所有
  2. 模糊查询:知识点是${ }连接占位符。这里导入了2个文件,即log4j-1.2.17.jar 和 log4j.properties(与mybatis.xml同目录)
  3. 插入数据:知识点是执行完sql语句后手动提交事务或获取session对象时选择不关闭自动提交的工厂方法。

7.Mybatis代理实现DAO开发?

原理:mapper的接口+mapper的映射

要求

  1. mapper接口和mapper的映射同包同名(注册映射时方便)
  2. mapper映射文件的namespace和接口的完全限定名保持一致
  3. 标签的id和方法的名称保持一致
  4. 标签的输入参数类型和方法的参数类型一致
  5. 标签的输出结果类型和方法的返回值类型一致

代码(配置文件版)

User类

package pojo;
public class User {
	private int uid;
	private String uname;
	private String password;
	public int getUid() {
		return uid;
	}
	public void setUid(int uid) {
		this.uid = uid;
	}
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	@Override
	public String toString() {
		return "User [uid=" + uid + ", " + (uname != null ? "uname=" + uname + ", " : "") + (password != null ? "password=" + password : "") + "]";
	}
}

UserMapper接口

package mapper;
import java.util.List;
import pojo.User;
public interface UserMapper {
	List<User> queryAll();
	User queryById(int uid);
}

UserMapper.xml文件(即UserMapper接口的映射文件,存放在mapper包下面哈,和UserMapper同包同名)

<?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="mapper.UserMapper">
	<select id="queryAll" resultType="User">
		select * from user
	</select>
	<select id="queryById" resultType="User">
		select * from user where uid=#{}
	</select>
</mapper>

Test类(获取配置,运行代码)

package test;
import java.io.IOException;
import java.io.Reader;
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 mapper.UserMapper;
public class Test {
	public static void main(String[] args) throws IOException {
		Reader reader = Resources.getResourceAsReader("mybatis.xml");
		SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
		SqlSession session = ssf.openSession();
		UserMapper mapper = session.getMapper(UserMapper.class);
		System.out.println(mapper.queryAll());
		session.close();
	}
}

代码(注解配置版)(关系比较简单时使用)

//在mapper接口中通过注解配置,就不需要mapper配置文件了!
//其他代码和配置仍然保持不变
public interface UserMapper {
	@Select("select * from user")
	List<User> queryAll();
	@Select("select * from user where uid=#{uid}")
	User queryById(int uid);
}

8.Mybatis高级映射

需求描述:查询部门及其部门下的所有员工。

映射分类:一对多和一对一

一对多:

  1. resultType特点
    1. 结果集中字段名称和类属性名称完全一致,此时将映射成功。
    2. 结果集中的字段和类的属性名称部分一致,部分映射成功。
    3. 结果集中的字段和类的属性名称都不一致,此时不会创建对象。
  2. 一对多:使用resultMap+collection标签

一对一:使用resultMap+association标签

代码实现

项目目录结构

pojo类:

package pojo;

import java.util.List;

public class Dept {
	private int deptno;
	private String dname;
	private String loc;
	private List<Emp> emps;
	public int getDeptno() {
		return deptno;
	}
	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}
	public String getDname() {
		return dname;
	}
	public void setDname(String dname) {
		this.dname = dname;
	}
	public String getLoc() {
		return loc;
	}
	public void setLoc(String loc) {
		this.loc = loc;
	}
	public List<Emp> getEmps() {
		return emps;
	}
	public void setEmps(List<Emp> emps) {
		this.emps = emps;
	}
	@Override
	public String toString() {
		return "Dept [deptno=" + deptno + ", " + (dname != null ? "dname=" + dname + ", " : "")
				+ (loc != null ? "loc=" + loc + ", " : "") + (emps != null ? "emps=" + emps : "") + "]";
	}
	
}

package pojo;

public class Emp {
	private int empno;
	private String ename;
	private String job;
	private int mgr;
	private String hiredate;
	private double sal;
	private double comm;
	private int deptno;
	private Dept dept;
	public int getEmpno() {
		return empno;
	}
	public void setEmpno(int empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public int getMgr() {
		return mgr;
	}
	public void setMgr(int mgr) {
		this.mgr = mgr;
	}
	public String getHiredate() {
		return hiredate;
	}
	public void setHiredate(String hiredate) {
		this.hiredate = hiredate;
	}
	public double getSal() {
		return sal;
	}
	public void setSal(double sal) {
		this.sal = sal;
	}
	public double getComm() {
		return comm;
	}
	public void setComm(double comm) {
		this.comm = comm;
	}
	public int getDeptno() {
		return deptno;
	}
	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}
	public Dept getDept() {
		return dept;
	}
	public void setDept(Dept dept) {
		this.dept = dept;
	}
	@Override
	public String toString() {
		return "Emp [empno=" + empno + ", " + (ename != null ? "ename=" + ename + ", " : "")
				+ (job != null ? "job=" + job + ", " : "") + "mgr=" + mgr + ", "
				+ (hiredate != null ? "hiredate=" + hiredate + ", " : "") + "sal=" + sal + ", comm=" + comm
				+ ", deptno=" + deptno + ", " + (dept != null ? "dept=" + dept : "") + "]";
	}
}

全局配置文件:mybatis.xml

<?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>
	<!-- 加载Java属性文件 -->
	<properties resource="jdbc.properties"></properties>
	<typeAliases>
		<package name="pojo"/>
	</typeAliases>
	<!-- 配置环境 -->
	<environments default="dev">
		<environment id="dev">
			<transactionManager type="JDBC"></transactionManager>
			<dataSource type="POOLED">
				<!-- name属性的值都是固定的,必须这么写,否则框架无法识别 -->
				<property name="driver" value="${driver}"/>
				<property name="url" value="${url}"/>
				<property name="username" value="${username}"/>
				<property name="password" value="${password}"/>
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<!-- 批量注册映射文件:mappr接口和映射文件必须同包同名 -->
		<package name="mapper"/>
	</mappers>
</configuration>

mappr:接口+映射文件

package mapper;
import java.util.List;
import pojo.Dept;
public interface DeptMapper {
	List<Dept> findDeptAndEmps();
}

package mapper;
import java.util.List;
import pojo.Emp;
public interface EmpMapper {
	List<Emp> findEmpAndDept();
}
<?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="mapper.DeptMapper">
	<!-- id:唯一标识    type:封装类型 -->
	<resultMap type="Dept" id="deptMap">
		<!--主键字段的映射    property:属性名称    column:结果集中字段名称    
			property的值必须与实体类中的属性名称一致,否则找不到setter访问器 -->
		<id property="deptno" column="deptno" />
		<result property="dname" column="dname" />
		<result property="loc" column="loc" />
		<!-- 将表中的数据封装到集合中  property:Dept类的属性  
			column:dept表和emp表的关联字段    ofType:dept类的属性emps集合中数据的类型 -->
		<collection property="emps" ofType="Emp" column="deptno">
			<id property="empno" column="empno" />
			<result property="ename" column="ename" />
			<result property="job" column="job" />
			<result property="mgr" column="mgr" />
			<result property="hiredate" column="hiredate" />
			<result property="sal" column="sal" />
			<result property="comm" column="comm" />
			<result property="deptno" column="deptno" />
		</collection>
	</resultMap>
	<!-- resultMap的值是上面resultMap标签的唯一标识id -->
	<select id="findDeptAndEmps" resultMap="deptMap">
		select * from dept left join emp on dept.deptno=emp.deptno
	</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="mapper.EmpMapper">
	<resultMap type="emp" id="empMap">
		<id property="empno" column="empno"/>
		<result property="ename" column="ename" />
		<result property="job" column="job" />
		<result property="mgr" column="mgr" />
		<result property="hiredate" column="hiredate" />
		<result property="sal" column="sal" />
		<result property="comm" column="comm" />
		<result property="deptno" column="deptno" />
		<!-- 将结果集封装到对象中     property:Emp类的属性  
			column:emp表和dept表的关联字段  javaType:Emp类的属性的数据类型-->
		<association property="dept" column="deptno" javaType="dept">
			<id property="deptno" column="deptno" />
			<result property="dname" column="dname"/>
			<result property="loc" column="loc"/>
		</association>
	</resultMap>
	<select id="findEmpAndDept" resultMap="empMap">
		select * from emp left join dept on dept.deptno=emp.deptno
	</select>
</mapper>

测试类:Test

package test;

import java.io.IOException;
import java.io.Reader;

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 mapper.DeptMapper;
import mapper.EmpMapper;

public class Test {
	public static void main(String[] args) throws IOException {
		Reader reader = Resources.getResourceAsReader("mybatis.xml");
		SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
		SqlSession session = ssf.openSession();
		
		DeptMapper mapper = session.getMapper(DeptMapper.class);
		System.out.println(mapper.findDeptAndEmps());
		
		EmpMapper mapper1 = session.getMapper(EmpMapper.class);
		System.out.println(mapper1.findEmpAndDept());
		session.close();
	}
}

猜你喜欢

转载自blog.csdn.net/qq_1018944104/article/details/83301439