【输入映射和输出映射】
1. 输入类型 parameterType
简单类型:int
pojo对象:自己写的,成员属性和数据库字段一一对应,有getset方法的类
pojo包装对象:QueryVo类,依赖pojo对象
package com.bwf.bean;
import java.util.ArrayList;
import java.util.List;
public class QueryVo {
private User user;
private List<Integer> list2 = new ArrayList<>();
private Integer[] array = null;
public Integer[] getArray() {
return array;
}
public void setArray(Integer[] array) {
this.array = array;
}
public List<Integer> getList2() {
return list2;
}
public void setList2(List<Integer> list) {
this.list2 = list;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
2. 输出类型
简单类型
pojo对象
pojo列表
3. resultMap
resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。
例子:如果我要查询所有订单,并附带相关的用户信息
注意:此时的pojo类里的用户id(userId)和数据库表里的用户id(user_id)并不一样,不改pojo类的属性名和数据库字段名的情况下,那么就可以使用resultmap
<resultMap id="ordersRm" type="Orders">
<result property="userId" column="user_id" />
</resultMap>
<!-- 查询所有订单 -->
<select id="queryAll" resultMap="ordersRm">
SELECT * FROM orders
</select>
复杂一点的resultmap在后面有讲
vo,dto和po的含义(不是同一个):
【动态SQL】
想根据条件搜索用户, 可以根据id 或名字 或生日 或性别 或地址 或任意组合搜索
这些都是基于OGNL 的表达式
1. if
在动态 SQL 中所做的最通用的事情是包含部分 where 字句的条件。比如:
<select id=”findActiveBlogWithTitleLike” parameterType=”Blog”
resultType=”Blog”>
SELECT * FROM BLOG
WHERE state = „ACTIVE‟
<if test=”title ! null ”>
AND title like #{title}
</if>
</select>
这条语句会提供一个可选的文本查找功能。如果你没有传递 title,那么所有激活的博客
都会被返回。但是如果你传递了 title,那么就会查找相近的 title(对于敏锐的检索,这中情
况下你的参数值需要包含任意的遮掩或通配符)的记录。
2. Where
where 元素知道如果由被包含的标记返回任意内容,就仅仅插入“WHERE”。而且,如
果以“AND”或“OR”开头的内容,那么就会跳过 WHERE 不插入。
<!-- 动态SQL -->
<!-- 根据条件搜索用户 -->
<select id="selectUserBy" parameterType="User" resultType="User">
<include refid="selectFromUser"></include>
<where>
<if test="id != null">
id = #{id}
</if>
<if test="username != null">
AND username = #{username}
</if>
<if test="sex != null">
AND sex = #{sex}
</if>
<if test="address != null">
AND address = #{address}
</if>
</where>
</select>
3. sql片段
这个元素可以被用来定义可重用的 SQL 代码段,可以包含在其他语句中。比如:
<sql id="selectFromUser">
SELECT id,username,birthday,sex,address FROM user
</sql>
这个 SQL 片段可以被包含在其他语句中,例如:
<select id="selectByName" parameterType="QueryVo" resultType="User">
<include refid="selectFromUser"></include>
WHERE username LIKE "%"#{user.username}"%"
</select>
4. foreach
foreach 元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可
以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素
是很智能的,它不会偶然地附加多余的分隔符。
注意:你可以传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做的时
候,MyBatis 会自动将它包装在一个 Map 中,用名称作为键。List 实例将会以“list”
作为键,而数组实例将会以“array”作为键
<!-- 查询指定id的用户集合 -->
<select id="queryByIds" resultType="User">
<include refid="selectFromUser"></include>
WHERE id IN
<foreach item="item" index="index" collection="list2"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
<select id="queryByIds2" resultType="User">
<include refid="selectFromUser"></include>
WHERE id IN
<foreach item="item" index="index" collection="array"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
定义的接口方法:
List<User> queryByIds(List<Integer> list);
List<User> queryByIds(QueryVo vo);
List<User> queryByIds2(Integer[] ids);
List<User> queryByIds2(QueryVo vo);
【Mybatis整合spring】
以后再学
【表和表的三种关系】
看的是记录的对应关系
1.一对多
一对多 - 用户对订单
多对一(一对一) 订单对用户
做法:
表结构设计:多方设置外键指向一方主键
用户表(一方) | 订单表(多方) | ||
Id | name | id | uid |
1 | 张三 | 1 | 1 |
2 | 李四 | 2 | 1 |
3 | 2 |
实体类
User{
private int id;
private String name;
// 一对多关系
private List<Order> orders;
}
Order{
private int id;
// 一对一关系
private User user;
}
2.双向一对一
(本质就是一张表,但是拆成了两张)
用户表 用户自我介绍表
id name age id 自我介绍
User{
id
name
age
自我介绍
}
3.多对多
学生表 | 课程表 |
张三 | 高等数学 |
李四 | 微积分 |
王五 | 计算机 |
表结构设计
学生表 | 中间表(选课表) | 课程表 | |||
id | sname | sid | lid | id | lname |
1 | 张三 | 1 | 1 | 1 | 高等数学 |
2 | 李四 | 1 | 2 | 2 | 微积分 |
3 | 王五 | 2 | 3 | 3 | 计算机 |
对象设计
Student{
private int id;
private String sname;
// 多对多 -> 一对多
private List<Lesson> lList;
}
Lesson{
private int id;
private String lname;
// 多对多 -> 一对多
private List<Student> sList;
}
两个成员保留哪个取决于业务要求
【关联查询】
1. 一对一
每一条订单记录对应一个用户
用mybatis就可以很好的获取数据,真的吗?
<select id="queryById" parameterType="int" resultMap="order_user">
SELECT o. *, u.username, u.birthday, u.sex, u.address
FROM orders o, user u
WHERE o.user_id = u.id
AND o.id = #{id};
</select>
结果发现打印出的tostring方法里面,user为空,为什么呢?
因为mybatis并不知道user表的id和orders表的userid是外键映射关系,所以就需要再添加一个resultmap建立两者之间的映射关系
<!-- 一对一 -->
<resultMap type="Orders" id="order_user">
<id property="id" column="id"/>
<result property="number" column="number"/>
<result property="createtime" column="createtime"/>
<result property="note" column="note"/>
<association property="user" column="user_id" javaType="User">
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</association>
</resultMap>
2. 一对多
每一个用户对应多条订单,写法如下
<!-- 多对多 -->
<resultMap type="User" id="user_order">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<collection property="orders" ofType="Orders">
<id property="id" column="oid"/>
<result property="number" column="number"/>
<result property="createtime" column="createtime"/>
<result property="note" column="note"/>
</collection>
</resultMap>
<select id="queryUserAndOrderByUid" parameterType="int" resultMap="user_order">
SELECT u.* , o.id oid, o.number, o.createtime, o.note
FROM user u LEFT JOIN orders o
ON u.id = o.user_id
WHERE u.id = #{id}
</select>
【逆向工程】
因为有了逆向工程的存在,我们不需要手动写pojo类,mapper映射文件和接口了,大大提高了开发速度.
通过已知的数据库表,逆向生成该表对应的pojo类,mapper映射xml文件和接口
暴力入门:
1.导入项目generatorSqlmapCustom
2.修改generatorConfig.xml文件
配置连接数据库参数
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/crm_ssm" userId="root"
password="root">
</jdbcConnection>
配置生成的pojo类存放到哪个包中
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="com.wowowo.bean"
targetProject=".\src">
<!-- 中间的属性略,暂时用不到 -->
</javaModelGenerator>
配置mapper映射文件的生成位置
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.wowowo.mapper"
targetProject=".\src">
<!-- 略 -->
</sqlMapGenerator>
配置mapper接口生成的位置
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.wowowo.mapper"
targetProject=".\src">
<!-- 略 -->
</javaClientGenerator>
指定数据库表
<!-- 指定数据库表 -->
<table schema="" tableName="cst_linkman"></table>
3.运行GeneratorSqlmap类
注意:逆向工程生成的mapper映射文件和接口不存在limit查询的sql语句,但是可以手动添加
生成的持久化对象中(POJO),多了一个xxxExample.java类,这个类是用来[构造复杂的筛选条件],通俗点讲就是[专门用来封装自定义查询条件],等会会介绍他的使用方法。
摘自:
https://www.cnblogs.com/whgk/p/7140638.html
a.在example类中添加以下属性和getset方法:
这2个属性是limit的2个参数
protected Integer off;
protected Integer len;
public Integer getOff() {
return off;
}
public void setOff(Integer off) {
this.off = off;
}
public Integer getLen() {
return len;
}
public void setLen(Integer len) {
this.len = len;
}
b.在xml文件中的id=selectByExample的sql标签中添加以下基于OGNL 的表达式
<!-- 注意:xml文件的空格,&&等字符无法直接显示,需要用转义字符来表达 -->
<!-- &表示& -->
<if test="off!=null && len!=null">
limit #{off} ,#{len}
</if>
逆向工程中生成的mapper对象的方法
查询
按照主键查找对应记录
selectByPrimaryKey(传入一个主键参数);
返回一条记录
按照一定条件查询(模糊查询:),用到了exampe(查询条件对象)
//这里以customer表,模糊查询custName字段带百记录的为例
//封装查询条件的对象在该类(xxxExample)中,所以先构造该对象
CstCustomerExample example = new CstCustomerExample();
//通过example的对象获取封装查询条件的对象Criteria
Criteria criteria = example.createCriteria();
//构建查询条件,这里使用方法将其内部实现封装了,其实做的事情就是在
//sql语句的where后面加入: and name like "%百%"
criteria.andCustNameLike("%" + "百" + "%");
//调用查询方法,传入查询条件example。
//构建查询条件,相当于在语句最后跟上where custIndustry= "教育行业"
criteria.andCustIndustryEqualTo("教育行业");
List<CstCustomer> poList = customerMapper.selectByExample(example);
//按照一定条件查询记录总数,如果传入空参,那么默认查询该表所有记录总数
CstCustomerExample example = new CstCustomerExample();
Criteria criteria = example.createCriteria();
int count=countByExample(example);
除此之外还有很多查询条件方法,就不一一列举了.
修改:
updateByPrimaryKeySelective :只更新model中不为空的字段
updateByPrimaryKey:将model中为空的字段也置为NULL
注意:在html中,某个text如果不填入值, 那么其实这个属性值只是长度为0,并不是空,这导致了我测试以上2个修改方法时发现效果是一样的.如果非要测试,那么可以把update方法作如下修改:
@Override
public void update(CstLinkman linkman) {
if(linkman.getLkmPhone().length()<=0){
linkman.setLkmPhone(null);
}
System.out.println(linkman);
linkmanMapper.updateByPrimaryKeySelective(linkman);
//linkmanMapper.updateByPrimaryKey(linkman);
}
添加
insert:只插入model中不为空的字段
insertSelective:所有字段都添加一遍即使没有值
删除:
deleteByExample(example):模糊删除
deleteByPrimaryKey(主键):根据主键删除