MyBatis

MyBatis

1.基础

1.介绍

是一个基于java的持久层框架,实现部分ORM功能.它是一个半自动ORM框架,Dao层实现可以不用自己写

2.优点
支持定制化SQL,存储过程以及高级映射设置 轻量级框架

可以使用简单的XML注解来配置映射信息,和sql语句

2.架构图

在这里插入图片描述

3.入门案例

1.流程

  • 引入3个jar包

    a. log4j-1.2.17.jar
    b. mybatis-3.4.6.jar
    c. mysql-connector-java-5.1.30-bin.jar

    • 创建 resources 目录
      a. 放入 log4j.properties 文件。 [文件包里直接导入]
      b. 创建 mysql.properties 文件。 [设置好数据库连接参数]
      c.创建 Mybatis.cfg.xml 文件
  • 创建实体类和数据表

  • 创建UserMapper.xml 文件

2.相关代码

**1.**Mybatis.cfg.xml 文件

<!-- 1. 加载 mysql 属性参数文件 -->
	<properties resource="mysql.properties"></properties>
<!-- 2.配置使用环境 defaulut="mysql"  默认使用数据库环境 -->
	<environments default="mysql">
		<environment id="mysql">
			<!-- 配置JDBC事务 -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 使用数据源连接池 -->
			<dataSource type="POOLED">
			<!--  配置数据连接 4 要参,参数名是 mybatis 预设的, 你不要去动。-->
				 <property name="driver" value="${jdbc.driverName}"/>
				 <property name="url" value="${jdbc.url}"/>
				 <property name="username" value="${jdbc.username}"/>
				 <property name="password" value="${jdbc.password}"/>
			</dataSource>
		</environment>
	</environments>	
<!-- 配置mappers标签 -->
	<mappers>
		<mapper resource="com/gec/domain/UserMapper.xml"/>
	</mappers>

2.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">
<!-- 上面是mapper.dtd 的模板内容 -->

<mapper namespace="com.gec.domain.UserMapper"> //命名空间要与mybatis.cfg.xml 中设置一致
	<insert id="addUser"> //插入语句
		insert into user(
			id,username,password,nickName,age,email,createDate
		)values(
		    null,#{username},#{password},#{nickName},#{age},#{email},now()
		)
	</insert>
</mapper>

3.测试类

1.加载Mybatis.cfg.xml
	InputStream is = Resources.getResourceAsStream("Mybatis.cfg.xml");
2.使用SqlSessionFactory构建器,创建会话工厂
	SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
3.通过会话工厂得到会话
	Session session = factory.openSession();
4.设置statement全限定名
	String namespace = "com.gec.domain.UserMapper";
	String statement = namespace+".addUser";
5.使用会话执行CURD操作
	int cnt = session.insert(statement,user);
6.提交事务
	session.commit();
7.关闭会话
	session.close();

4.增删改查

注意:statement == 命名空间+ .stateId

​ String namespace = “com.gec.domain.UserMapper”;
​ String statement = namespace+“.deleteUser”;

1.insert操作

  • xml文件中使用标签
  • 调用session的方法: session.insert(statement); /session.insert(statement,输入参数); //操作定位符
<insert id="addUser">    // xml文件中 使用 insert标签
		insert into user(
			id,username,password,nickName,age,email,createDate
		)values(
		    null,#{username},#{password},#{nickName},#{age},#{email},now()
		)
</insert>
操作定位符
session.insert(statement,user);
  • 插入数据并得到生成的id
    • keyProperty:告诉mybatis哪个是主键
    • useGeneratedKeys:成功插入数据后,得到生成的主键值,并赋值给对象上
<insert id="addUserAndGetId" keyProperty="id" useGeneratedKeys="true"> //id为主键
		insert into user(
			id,username,password,nickName,age,email,createDate
		)values(
		    null,#{username},#{password},#{nickName},#{age},#{email},now()
		)
</insert>

2.delete操作

  • xml文件中 使用 delete标签
  • session.delete(stateId)/session.delete(stateId,入参) //没有设置占位符则不入参
xml文件中
<delete id="deleteUser">
		delete from user where id=#{id}
</delete>
session.delete(statement, 9);

3.update操作

  • xml文件中使用update标签
  • session.update(statement);/session.update(statement, user);//没有设置占位符则不入参
<update id="updateUser">
		update user set 
		username=#{username},password=#{password},nickName=#{nickName},age=#{age},
		email=#{email}
		where id=#{id}
</update>

session.update(statement, user)

注意:

  • sql设置了占位参数,但对象属性为null时,执行完sql,记录对应字段会设置为null
  • 属性值为基础类型时,没有赋值,对应字段设置为0/0.0,尽量不要设置为基本数据类型
  • 不管任何标签都能做任何事,不管任何方法都能做任何事
    • xml中设置了update标签,但是调用了session.selectOne()方法同样能修改数据库
    • xml中设置了update标签,但是里面的sql语句为删除语句,此时是删除数据库数据

5.自动映射

1.从数据库到程序

1.原理

  • 先找对应的setXXX方法,有则通过反射调用set方法设置Pojo属性
  • 要是没有则找对应属性名,有则直接反射字段赋值,没有则为 null (不会报错)
  • 类中要有无参构造器,否则会报错

2.从程序到数据库

1.原理

程序(内存) --> 写入到数据库

  • 先找输入对象的对应getXXX方法,有则通过反射调用getXXX获取Pojo属性,并填入SQL
  • 若无get方法,则看有无对应字段,有则直接反射获取字段值设置到SQL语句
  • 要是都没有则报错
  • 看有无get方法–>没有,看有无对应属性名–>没有,报错 //有则设置到SQL语句
    在这里插入图片描述

6.输入类型入参

1.入参到哪里

使用 Map/Pojo 承载数据,并填入下面
<insert id="addUser">
		insert into user(
			id,username,password,nickName,age,email,createDate
		)values(
		    null,#{username},#{password},#{nickName},#{age},#{email},now()
		)
</insert>

2.入参方式

  • 使用map承载数据(多个参数时),并用map入参

    Map p = new HashMap();
    p.put("id", 1);
    p.put("username", "林");
    session.update(statement, p);
    
  • 使用JavaBean承载数据(多个参数时),并用 属性名和get()方法入参(POJO入参)

    Person p = new Person();
    person.setId(2);
    person.setUsername("王");
    session.update(statement, p);
    
  • 使用基础数据与包装类承载数据入参(一个参数时)

7.输出类型出参

1.出参原理

在这里插入图片描述

2.出参方式

  • 基础类型 //输出结果是基础类型

    <select id="getPerson" resultType="string">
    		select username from person where id=#{id}
    </select>             
    
  • Map类型 //输出结果是Map

    <select id="getPersonToMap" resultType="java.util.Map">
    		select * from person where id=#{id}
    </select>
    
  • POJO类型

9.获取多条记录

1.使用事项

  • selectOne:查询结果只有一条记录则使用这个,若有多条则会报错
    • ​ session.selectOne(statement,1); //查询id为1的Person
  • selectList:查询结果有多条记录使用该方法
    • List list = session.selectList(statement); //查询所有
    • resultType=“list中装载的数据类型”

MyBatis动态代理开发

1.传统方法弊端

Dao层中实现类的getUserById方法要做的事 步骤太过繁琐

1.获取connection;2.编写sql语句;3.获取statement;4.执行sql;5.得到结果集;6.封装User,添加到List集合
7.关闭psmt,rs;8.返回List<User>

在这里插入图片描述

2.什么是动态代理开发

  • 结合动态代理技术创建代理对象的生成技术,实现Dao接口层的实现类的自动创建,并通过Mybatis的API

自动关联Mapper映射器中的statement,从而实现与数据库的交互,便是Mybatis的动态代理开发模式.

  • 要提供Mapper的操作接口,提供Mapper映射器配置文件或使用注解

3.遵循的开发约定

1.命名空间

namespace=“接口全类名” //com.gec.mapper.UserMapper

2.接口方法名

要与statementId一致

<select id="getUser" ...>
public User  getUser(){...}

3.入参保证

在SQL中的占位参数,必须能从传入的参数中找到 #{XXX}

a.通过位置匹配(传入多个参数)

b.通过key匹配

c.通过getXXX匹配

d.通过属性名匹配

4.出参保证

保证类型一致

a.resultType=“泛型中类型”

b.resultType=“方法的返回类型”

配置格式

<mapper namespace="接口全类名">
	<select id="接口方法名" resultType="返回类型/泛型类型">
		select * from user where age>#{age}  and username=#{username}
	</select>
</mapper>

注意事项

  • xml文件中statementID不能有相同的否则会报错
  • 接口类中可以有重名方法,根据入参的数据选择调用哪个方法

4.多参数绑定

  • 单个参数

    #{占位符名称} 可以随意设置,#{a},#{b},#{c}

  • 多个参数

    • 索引入参

      List<User> getUserByManyPara(String nickName, int age );
      			      				 [arg0]     [arg1]
      			      				 [param1]   [param2]
      select * from user where nickName=#{ arg0 } and age &gt; #{ arg1 }
      
    • 注解入参

      List<User> getUserByManyPara(
      			@Param("_nickName")String nickName, 
      			@Param("_age")int age );  
      select * from user where nickName=#{ _nickName } and age &gt; #{ _age }	//&gt;代表 > &t;代表 <
      resultType="别名"
      

MyBatis进阶

1.核心配置文件

1.别名设置

内置别名

Alias(别名)Mapped type Java类型
_bytebyte
_long _short _int _integerlong/short/int/integer
_double _float _booleandouble/float/boolean
string /byte /booleanString/Byte/Boolean
long/short/int/integerLong/Short/Integer/Integer
double/float/dateDouble/Float/Date
map/hashmapMap/HashMap
list/arraylistList/ArrayList

自定义别名

格式:在mybatis.cfg.xml文件中

​ 单独声明一个别名映射:

​ 包扫描方式批量声明:

<typeAliases>
		<typeAlias type="com.gec.domain.User" alias="user"/>
</typeAliases>
resultType="user"

2.映射文件注册

  • location=“xml地址”

  • map接口 class=“mapper地址”

  • 包扫描方式

映射文件注册方式Mapper.xml文件是否要与接口名相同是否要在同一个包
location=“xml地址”不需要不需要
class=“mapper地址”需要需要
包扫描方式需要需要

2.结果集映射器

1.使用场景

表列名与类属性名不一致时,需要提供映射处理器来作数据映射,我们可以自己定义一套映射规则

2.格式

<resultMap type="com.gec.domain.User" id="getHandler">
		<id column="_id" property="id"/>
		<result column="user_name" property="username"/>
		<result column="_password" property="password"/>
</resultMap>

3.有参映射器

  • 提供有参构造器–>提供对应映射处理器–>在标签中引用
<resultMap type="com.gec.domain.User" id="userResult">
		<constructor>
			<idArg column="_id" javaType="string"/>
			<arg column="user_name" javaType="string"/>
			<arg column="_password" javaType="string"/>
			<arg column="_age" javaType="integer"/>
		</constructor>
	</resultMap>

==注意:==数据类型要与有参构造器里的一致,并且顺序也要一致!

3.参数映射器

4.动态SQL

1.什么是动态SQL

能够按照逻辑与规则,根据输入条件,来动态生成SQL语句

2.引用SQL片段

标签:设置SQL代码片段

标签:引用SQL代码片段

	<sql id="field">	//设置SQL片段
		id,username,password,age
	</sql>
	<sql id="values">
		#{id},#{username},#{password},#{age}
	</sql>

	<insert id="getUserPar">
		insert into user(
			<include refid="field"/> //引用SQL片段
		)values(
			<include refid="values"/>
		)
	</insert>

3.if条件设置

sql语句

5.#号和$号

1.#号应用

“%”#{username}“%” --> 最终得到: ‘%andy%’

使用#号做占位符,入参的参数类型可以是字符串,user对象,Map…

<select id="getUser" resultType="com.gec.domain.User">
		select * from user where age>#{age}  and username="%"#{username}"%"
</select>

2.$号应用

‘%${username}%’ --> 最终得到: ‘%andy%’ //不用添加双引号

使用$ 号做占位符,要求传POJO对象,通过 ${username}取user的name属性

<select id="getUser" resultType="com.gec.domain.User">
		select * from user where age>#{age}  and username='%${username}%'
</select>

3.两者区别

1.只有单一参数

取参方式${}#{}
arg0不行ok
param1不行ok
KEY键不匹配不行,键匹配OK键不匹配ok,键匹配OK//${aa}不行 #{aa}ok

2.有多个参数

取参方式${}#{}
arg0okok
param1okok
Key键匹配OK键匹配OK

MyBatis表关联

1.一对多

1.配置说明

  • 使用左外连接查询数据库
  • 在 resultMap 中来封装部门基础数据。
  • resultMap中使用来封装 List中的数据
  • 中设置:
    • 格式:<collection …节点属性项> 设置List所存储对象的属性
  • property=“属性名”
  • ofType=“Java类型”//泛型中的类型
  • column=“外键列名”
<resultMap type="com.gec.domain.Dept" id="DeptResultHandler">
		<id column="_id" property="id"/>  //封装部门的基本数据
		<result column="dept_name" property="deptName"/>
		<result column="_descript" property="descript"/>
		<collection property="emps" ofType="com.gec.domain.Employee"> //封装List中的数据
			<id column="emp_id" property="id"/>
			<result column="emp_name" property="empName"/>
		</collection>
	</resultMap>

2.多对一

1.association标签

  • 功能:用来发出另外一个子查询
  • 常规设置项
    • peoperty=“属性名”
    • column=“列名” 传入子查询的入参
    • javaType=“入参类型”
    • select=“statement_id” 另一条子查询

a.

  • 单查员工表的数据 输出类型=“结果集处理器” -> EmployeeResultHandler

b.结果集处理器

  • 封装基础数据
  • association 关联另一条查询。

    select 还可以关联另一个命名空间中查询。

c. 子查询

  • 用来查询部门表的数据, 根据 id id 从 association 中的column=“xxx” 来的。

d. 在另外一个 resultMap 中封装部门数据。

a.	<select id="getEmpById" resultMap="EmpResult">
		select * from t_employee e 
		where e._id=#{id}
	</select>
	
b.	<resultMap type="com.gec.domain.Employee" id="EmpResult">
		<id column="_id" property="id"/>
		<result column="emp_name" property="empName"/>
		<association property="dept"
			column="dept_id" javaType="com.gec.domain.Dept"
			select="queryDeptById"/>
		
	</resultMap>
	
c.	<select id="queryDeptById" resultMap="DeptResult">
		select * from t_dept d
		where d._id = #{id}
	</select>
d.	<resultMap type="com.gec.domain.Dept" id="DeptResult">
		<id column="_id" property="id"/>
		<result column="dept_name" property="deptName"/>
		<result column="_descript" property="descript"/>
	</resultMap>

3.多对多

a. 命名空间: com.gec.mapper.CourseMapper

b.
1)同时查询三表的数据
【1】t_course
【2】t_student_course
【3】t_student
优先查询 课程 表, 就算没有学生选修这门课程, 也能得到 [课程对象]。
2)选取数据时, 把两个 _id 去掉。
2)输出类型=“courseMap”

c. 结果集处理器 [courseMap]。

  • 先封装 Course 基础数据 .选择中间表的 xx_id, 填入 id 项属性。

  • 再封装 Collection 关联数据.选择中间表的 xx_id, 填入 id 项属性。

	<select id="getCourceById" resultMap="CourceMap">
		select sc.*,c.cource_name,s.student_name from t_cource c
		left join t_student_cource sc on c.id = sc.crs_id
		left join t_student s on s._id= sc.stu_id
		where c.id=#{id}
	</select>
	
	<resultMap type="com.gec.domain.Cource" id="CourceMap">
		<id column="crs_id" property="id"/>
		<result column="cource_name" property="courceName"/>
		<collection property="students"
					ofType="com.gec.domain.Student"
					column="stu_id">
		<id column="stu_id" property="id"/>
		<result column="student_name" property="studentName"/>
		</collection>
	</resultMap>

4.分页插件

1.介绍

分页插件是 mybatis 中用处理分页功能的功能插件, 作为一个插件来使用。

2.前期准备

1.jar包
在这里插入图片描述

2.mybatis.cfg.xml

放在别名标签后面,环境标签前面

<typeAliases>...</typeAliases>
<plugins>
	 	<plugin interceptor="com.github.pagehelper.PageHelper">
	 		<property name="dialect" value="mysql" />
	 		<property name="offsetAsPageNum" value="false" />
			<property name="rowBoundsWithCount" value="false" />
			<property name="pageSizeZero" value="true" />
	 		<property name="reasonable" value="false"/>
	 		<property name="supportMethodsArguments" value="false" />
	 		<property name="returnPageInfo" value="none" />
		 </plugin>
 </plugins>
 <environments>...</environments>

3.注意事项

  • PageHelper.startPage(页码, 页大小,是否查询记录数); 每开一次执行一次,自动插入分页的SQL代码
  • startPage只应用在最近一次查询,第二次无效
  • 不要让流程语句干扰分页执行
  • 获取分页信息
    • 总记录数:page.getTotal();
    • 总页数:page.getPages();
  • 先查询,再获取总记录数,总页数,否则结果为0
Page<Object> page=PageHelper.startPage(1, 5,true);
List<Employee>  list= mapper.getEmployees();
list.forEach(System.out::println);
System.out.println("总记录数:"+page.getTotal());
System.out.println("总页数:"+page.getPages());

5.反向工程

1.介绍

反向工程即是根据数据库中的表结构,表关系来生成mybatis相关的资源文件

(POJO类,映射器配置文件,动态代理接口,操作样本类)

注意;只用于单表操作,多表关系要自己配置

2.jar包和配置文件

在xml文件中的配置

  • 数据库连接参数,地址,密码等
  • 配置生成实体类的存放位置
  • mapper映射文件存放位置
  • 动态代理文件的位置
  • 数据表

6.示例方法

1.增删改查方法

SqlSession session = getSession();
UserMapper mapper = session.getMapper(UserMapper.class); //获取mapper对象

  • mapper.insert(user);
  • mapper.deleteByPrimaryKey(9);
  • mapper.updateByPrimaryKey(user);
  • mapper.selectByPrimaryKey(2);

2.更新样式方法

根据样本中设置的条件执行更新

  • 根据条件样本更新数据

    mapper.updateByExample(实体对象, Bean样本); 该方法会清空其他属性的数据,相当于重新插入一个数据,不用提供id

  • 根据条件锁定更新目标,根据属性是否有值更新字段

    mapper.updateByExampleSelective(实体对象, Bean样本); 该方法直接在找到的数据上修改,不用提供id

  • 直接更新数据

    mapper.updateByPrimaryKey(user); 会清空同一数据的其他属性,需要提供id

    mapper.updateByPrimaryKeySelective(user);不会清空同一数据的其他属性,需要提供id

3.查询数据

  • 根据样本条件查询数据

    mapper.selectByExample(ue); cri.andUserNameIn(list);//list中有的名字

  • 根据Id查询

    mapper.selectByPrimaryKey(5);

1.增删改查方法

SqlSession session = getSession();
UserMapper mapper = session.getMapper(UserMapper.class); //获取mapper对象

  • mapper.insert(user);
  • mapper.deleteByPrimaryKey(9);
  • mapper.updateByPrimaryKey(user);
  • mapper.selectByPrimaryKey(2);

2.更新样式方法

根据样本中设置的条件执行更新

  • 根据条件样本更新数据

    mapper.updateByExample(实体对象, Bean样本); 该方法会清空其他属性的数据,相当于重新插入一个数据,不用提供id

  • 根据条件锁定更新目标,根据属性是否有值更新字段

    mapper.updateByExampleSelective(实体对象, Bean样本); 该方法直接在找到的数据上修改,不用提供id

  • 直接更新数据

    mapper.updateByPrimaryKey(user); 会清空同一数据的其他属性,需要提供id

    mapper.updateByPrimaryKeySelective(user);不会清空同一数据的其他属性,需要提供id

3.查询数据

  • 根据样本条件查询数据

    mapper.selectByExample(ue); cri.andUserNameIn(list);//list中有的名字

  • 根据Id查询

    mapper.selectByPrimaryKey(5);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值