建网站什么网最好,建筑认证,tp5网站开发模板,1做网站MyBatis整理 篇一.MyBatis环境搭建与增删改查 篇二.MyBatis查询与特殊SQL 篇三.自定义映射resultMap和动态SQL 篇四.MyBatis缓存和逆向工程 文章目录1、自定义映射P1:测试数据准备P2:字段和属性的映射关系P3:多对一的映射关系P4:一对多的映射关系2、动态SQL2.1 IF标签2.2 w… MyBatis整理 篇一.MyBatis环境搭建与增删改查 篇二.MyBatis查询与特殊SQL 篇三.自定义映射resultMap和动态SQL 篇四.MyBatis缓存和逆向工程 文章目录1、自定义映射P1:测试数据准备P2:字段和属性的映射关系P3:多对一的映射关系P4:一对多的映射关系2、动态SQL2.1 IF标签2.2 where标签2.3 trim标签2.4 choose、when、otherwise标签2.5 foreach标签2.6 SQL标签1、自定义映射
若字段名和实体类的属性名不一致则需要自定义映射。
P1:测试数据准备
员工表 部门表
定义对应的实体类注意字段名是下划线命名属性名是驼峰命名不再一致了
定义Mapper接口和映射文件 P2:字段和属性的映射关系
当字段名和实体类中的属性名不一致但是字段名符合数据库的规则使用_实体类中的属性名符合Java的规则使用驼峰此时使用之前的自动映射resultType则命名不一致的属性值为null解决思路有三种 思路一给字段名起别名使其和属性名保持一致 !--ListEmp getAllEmp();--
select idgetAllEmp resultTypeEmpselect eid,emp_name empName,age,sex,email from t_emp
/select 思路二设置全局配置将下划线_自动映射为驼峰 在核心配置文件mybatis-config.xml中
settings!--将表中字段的下划线自动转换为驼峰--setting namemapUnderscoreToCamelCase valuetrue/
/settings!--注意这种只能转换规范命名即emp_name映射为empName--此时SQL语句正常写即可。 思路三使用resultMap不再使用之前的resultType做自动映射 resultMap idempResultMap typeEmpid propertyeid columneid/idresult propertyempName columnemp_name/resultresult propertyage columnage/resultresult propertysex columnsex/resultresult propertyemail columnemail/result
/resultMap
!--ListEmp getAllEmp();--
select idgetAllEmp resultMapempResultMapselect * from t_emp
/select!--注意别只写不一样的属性一样的也得写一遍--resultMap即设置自定义映射关系 属性 。 id我定义的映射的唯一标识不能重复给select标签中的resultMap属性用 。 type查询的数据要映射的实体类的类型 子标签 。 id设置主键的映射关系 。 result设置普通字段的映射关系 子标签属性 。 property设置映射关系中实体类中的属性名 。 column设置映射关系中表中的字段名
运行结果
P3:多对一的映射关系
多对一的时候在’多’的这边设置设置’一’所对应的对象在’一’那边设置’多’的对象集合 。处理多对一的映射关系如查询企业员工信息及其部门有三种实现方式
public class Emp { private Integer eid; private String empName; private Integer age; private String sex; private String email; /*** 这里设置一所对应的对象*/private Dept dept;//...构造器、get、set方法等
} 思路一使用级联属性赋值 resultMap idempAndDeptResultMapOne typeEmpid propertyeid columneid/idresult propertyempName columnemp_name/resultresult propertyage columnage/resultresult propertysex columnsex/resultresult propertyemail columnemail/resultresult propertydept.did columndid/resultresult propertydept.deptName columndept_name/result
/resultMap
!--Emp getEmpAndDept(Param(eid)Integer eid);--
select idgetEmpAndDept resultMapempAndDeptResultMapOneselect * from t_emp left join t_dept on t_emp.did t_dept.did where t_emp.eid #{eid}
/select 思路二通过association处理多对一的映射 association处理多对一映射关系property需要处理多对一映射关系的属性名javaType该属性的类型
resultMap idempAndDeptResultMapTwo typeEmpid propertyeid columneid/idresult propertyempName columnemp_name/resultresult propertyage columnage/resultresult propertysex columnsex/resultresult propertyemail columnemail/resultassociation propertydept javaTypeDeptid propertydid columndid/idresult propertydeptName columndept_name/result/association
/resultMap
!--Emp getEmpAndDept(Param(eid)Integer eid);--
select idgetEmpAndDept resultMapempAndDeptResultMapTwoselect * from t_emp left join t_dept on t_emp.did t_dept.did where t_emp.eid #{eid}
/select
以上的逻辑是在association中写要处理多对一关系的属性名dept再说明该属性的Java类----知道类型通过反射拿到该类型的属性did和deptName----将查询出来的字段赋值给属性----Dept类的对象有了----赋值给属性dept 思路三分步查询处理多对一的映射 先查询员工信息–拿到部门id–根据部门id查询部门信息—将信息赋值给dept属性
引用属性--那个属性的值也是一个对象丈夫是一个对象:
有姓名属性、年龄属性、妻子属性。妻子属性就是一个引用属性里面是个对象有它自己的属性//EmpMapper里的方法
/*** 通过分步查询员工及所对应的部门信息* 分步查询第一步查询员工信息*/
Emp getEmpAndDeptByStepOne(Param(eid) Integer eid);
property即要处理多对一映射关系的属性名select即设置分布查询的sql的唯一标识namespace.SQLId或mapper接口的全类名.方法名column设置分布查询的条件要根据员工表的did去查询部门信息即第二个SQL要根据什么去查
resultMap idempAndDeptByStepResultMap typeEmpid propertyeid columneid/idresult propertyempName columnemp_name/resultresult propertyage columnage/resultresult propertysex columnsex/resultresult propertyemail columnemail/resultassociation propertydeptselectcom.llg.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwocolumndid/association
/resultMap
!--Emp getEmpAndDeptByStepOne(Param(eid) Integer eid);--
select idgetEmpAndDeptByStepOne resultMapempAndDeptByStepResultMapselect * from t_emp where eid #{eid}
/select
第二步
//DeptMapper里的方法
/*** 通过分步查询员工及所对应的部门信息* 分步查询第二步通过did查询员工对应的部门信息* 这里的查询结果要给Emp的dept属性赋值所以返回类型Dept*/
Dept getEmpAndDeptByStepTwo(Param(did) Integer did);
!--此处的resultMap仅是处理字段和属性的映射关系,不想写就开启setting后使用resultType--
resultMap idEmpAndDeptByStepTwoResultMap typeDeptid propertydid columndid/idresult propertydeptName columndept_name/result
/resultMap
!--Dept getEmpAndDeptByStepTwo(Param(did) Integer did);--
select idgetEmpAndDeptByStepTwo resultMapEmpAndDeptByStepTwoResultMapselect * from t_dept where did #{did}
/select
测试类
Test
public void testGetEmpAndDeptByStep() {SqlSession sqlSession SqlSessionUtils.getSqlSession();EmpMapper empMapper sqlSession.getMapper(EmpMapper.class);Emp emp emmpMapper.getEmpAndDeptByStepOne(5);System.out.println(emp);
}
运行结果 梳理下逻辑 分步查询的好处–延迟加载 分步查询实现一个功能分了两步但这两步各自也是一个单独的功能。这就分步查询的好处—实现延迟加载
在核心配置文件中配置全局信息setting标签
lazyLoadingEnabled延迟加载的全局开关。当开启时所有关联对象都会延迟加载aggressiveLazyLoading当开启时任何方法的调用都会加载该对象的所有属性。 否则每个属性会按需加载
settings!--开启延迟加载--setting namelazyLoadingEnabled valuetrue/setting nameaggressiveLazyLoading valuefalse/
/settings
此时我只获取员工名称可以发现第二句SQL并未执行这就是按需加载获取的数据是什么就只会执行相应的sql 而当获取部门信息的时候两句就都会执行。为了清晰看到效果先关掉延迟加载可以看到是两句SQL都执行完了再拿数据
再开启延迟加载可以看到是先执行了一句SQL拿到了员工姓名后面需要部门信息的时候又执行了第二句SQL这就是按需加载 更改了全局设置是否延迟加载则是对所有SQL的。当开启了全局的延迟加载注意fetchType的前提是开启全局要想单独控制某一个可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载
fetchType“lazy(延迟加载)”fetchType“eager(立即加载)”
P4:一对多的映射关系
多对一的时候在’多’的这边设置设置’一’所对应的对象在’一’那边设置’多’的对象集合 。
public class Dept {private Integer did;private String deptName;//多的类型的集合private ListEmp emps;//...构造器、get、set方法等
} 思路一使用collection collection处理一对多的映射关系ofType表示该属性所对应的集合中存储的数据的类型
public interface DeptMapper{/*** 查询部门即其下的所有员工信息*/Dept getDeptAndEmp(Param(did) Integer did);
}resultMap idDeptAndEmpResultMap typeDeptid propertydid columndid/idresult propertydeptName columndept_name/resultcollection propertyemps ofTypeEmpid propertyeid columneid/idresult propertyempName columnemp_name/resultresult propertyage columnage/resultresult propertysex columnsex/resultresult propertyemail columnemail/result/collection
/resultMap
!--Dept getDeptAndEmp(Param(did) Integer did);--
select idgetDeptAndEmp resultMapDeptAndEmpResultMapselect * from t_dept left join t_emp on t_dept.did t_emp.did where t_dept.did #{did}
/select 思路二分步查询 第一步
public interface DeptMapper{/*** 通过分步查询查询部门及对应的所有员工信息* 分步查询第一步查询部门信息*/Dept getDeptAndEmpByStepOne(Param(did) Integer did);
}
resultMap idDeptAndEmpByStepOneResultMap typeDeptid propertydid columndid/idresult propertydeptName columndept_name/resultcollection propertyempsselectcom.llg.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwocolumndid/collection
/resultMap
!--Dept getDeptAndEmpByStepOne(Param(did) Integer did);--
select idgetDeptAndEmpByStepOne resultMapDeptAndEmpByStepOneResultMapselect * from t_dept where did #{did}
/select
第二步
public interface EmpMapper{/*** 通过分步查询查询部门及对应的所有员工信息* 分步查询第二步根据部门id查询部门中的所有员工*/ListEmp getDeptAndEmpByStepTwo(Param(did) Integer did);
}
!--ListEmp getDeptAndEmpByStepTwo(Param(did) Integer did);--
select idgetDeptAndEmpByStepTwo resultTypeEmpselect * from t_emp where did #{did}
/select
结果 当然分布查询在这儿也可以得到验证 2、动态SQL
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能它存在的意义是为了解决拼接SQL语句字符串时的痛点问题
2.1 IF标签
public interface DynamicSQLMapper{/*** 多条件查询*/ListEmp getEmpByCondition(Emp emp);
}if标签可通过test属性对表达式进行判断若表达式的结果为true则标签中的内容会拼接到SQL中反之标签中的内容不会拼接。在where后面添加一个恒成立条件11这个条件不会影响查询结果而又可以很好的拼接后面的SQL当empName传过来为空select * from t_emp where and age ? and sex ? and email ?此时where与and连用SQL语法错误
!--ListEmp getEmpByCondition(Emp emp);--
select idgetEmpByCondition resultTypeEmpselect * from t_emp where 11if testempName ! null and empName !and emp_name #{empName}/ifif testage ! null and age !and age #{age}/ifif testsex ! null and sex !and sex #{sex}/ifif testemail ! null and email !and email #{email}/if
/select
测试
2.2 where标签
当where标签中有内容时会自动生成where关键字并将内容前多余的and或者or去掉而当where标签中没内容时where关键字也就不再生成。
!--ListEmp getEmpByCondition(Emp emp);--
select idgetEmpByCondition resultTypeEmpselect * from t_empwhereif testempName ! null and empName !emp_name #{empName}/ifif testage ! null and age !and age #{age}/ifif testsex ! null and sex !and sex #{sex}/ifif testemail ! null and email !and email #{email}/if/where
/select
where标签和if标签一般配合使用
若where标签中的if条件都不满足则where标签没有任何功能即不会添加where关键字若where标签中的if条件满足则where标签会自动添加where关键字并将条件最前方多余的and/or去掉
!--这种用法是错误的只能去掉条件前面的and/or条件后面的不行--
if testempName ! null and empName !
emp_name #{empName} and
/if
if testage ! null and age !age #{age}
/if
当empName有值age为空则SQL为
select * from d_emp where emp_namellg and
//此处where标签去不掉and了2.3 trim标签
trim用于去掉或添加标签中的内容当标签中有内容的时候
prefix在trim标签中的内容的前面添加某些指定内容suffix在trim标签中的内容的后面添加某些指定内容prefixOverrides在trim标签中的内容的前面去掉某些指定内容suffixOverrides在trim标签中的内容的后面去掉某些指定内容
当标签中没有内容的时候trim标签也没有任何效果
!--ListEmp getEmpByCondition(Emp emp);--
select idgetEmpByCondition resultTypeEmpselect * from t_emptrim prefixwhere suffixOverridesand|orif testempName ! null and empName !emp_name #{empName} and/ifif testage ! null and age !age #{age} and/ifif testsex ! null and sex !sex #{sex} or/ifif testemail ! null and email !email #{email}/if/trim
/select
测试类
//测试类
Test
public void getEmpByCondition() {SqlSession sqlSession SqlSessionUtils.getSqlSession();DynamicSQLMapper mapper sqlSession.getMapper(DynamicSQLMapper.class);ListEmp emps mapper.getEmpByCondition(new Emp(null, 甲, null, null, null, null));System.out.println(emps);
} 2.4 choose、when、otherwise标签
choose…when…otherwise相当于if…else if…else
when即if或者else if至少要有一个when后面的test条件成立则拼接otherwise相当于else最多只能有一个
select idgetEmpByChoose resultTypeEmpselect * from t_empwherechoosewhen testempName ! null and empName ! emp_name #{empName}/whenwhen testage ! null and age ! age #{age}/whenwhen testsex ! null and sex ! sex #{sex}/whenwhen testemail ! null and email ! email #{email}/whenotherwisedid 1/otherwise/choose/where
/select
!--注意这里不用加and或者or了没意义if分支中一个就结束了--测试程序
Test
public void getEmpByChoose() {SqlSession sqlSession SqlSessionUtils.getSqlSession();DynamicSQLMapper mapper sqlSession.getMapper(DynamicSQLMapper.class);ListEmp emps mapper.getEmpByChoose(new Emp(null, , null, , , null));System.out.println(emps);
}
结果
2.5 foreach标签
foreeach标签的属性有
collection设置要循环的数组或集合item表示集合或数组中的每一个数据separator设置循环体之间的分隔符分隔符前后默认有一个空格如,open设置foreach标签中的内容的开始符close设置foreach标签中的内容的结束符 通过数组实现批量删除 public interface DynamicSQLMapper{/*** 通过数组实现批量删除*/int deleteMoreByArray(ListInteger eids);
}只论SQL批量删除的实现可以通过以下两种写法
delete from t_emp where eid in (6,7,8);delte from t_emp where eid6 or eid7 or eid8;关于第一种SQL的实现 优化一下
!--int deleteMoreByArray(Integer[] eids);--
delete iddeleteMoreByArraydelete from t_emp where foreach collectioneids itemeid separatororeid #{eid}/foreach
/delete
关于第二种SQL的实现
!--int deleteMoreByArray(Integer[] eids);--
delete iddeleteMoreByArraydelete from t_emp where eid inforeach collectioneids itemeid separator, open( close)#{eid}/foreach
/delete测试
Test
public void deleteMoreByArray() {SqlSession sqlSession SqlSessionUtils.getSqlSession();DynamicSQLMapper mapper sqlSession.getMapper(DynamicSQLMapper.class);int result mapper.deleteMoreByArray(new Integer[]{6, 7, 8});System.out.println(result);
}
结果 通过集合实现批量插入 public interface DynamicSQLMapper{/*** 通过集合实现批量添加*/int insertMoreByList(ListEmp emps);
}只说SQL写法应该是
insert into t_emp values(a1,a2,a3),(b1,b2,b3),(v1,v2,v3);
使用foreach动态实现
!--int insertMoreByList(Param(emps) ListEmp emps);--
insert idinsertMoreByListinsert into t_emp valuesforeach collectionemps itememp separator,(null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null)/foreach
/insert
注意这里不用open和close批量插入的原SQL是每条数据中有括号即每次循环有括号而不是删除SQL中的开头和结尾有括号。
//测试程序
Test
public void insertMoreByList() {SqlSession sqlSession SqlSessionUtils.getSqlSession();DynamicSQLMapper mapper sqlSession.getMapper(DynamicSQLMapper.class);Emp emp1 new Emp(null,a,1,男,123321.com,null);Emp emp2 new Emp(null,b,1,男,123321.com,null);ListEmp emps Arrays.asList(emp1, emp2);int result mapper.insertMoreByList(emps);System.out.println(result);
}
结果
2.6 SQL标签
在映射文件中声明一段SQL片段把常用的一段SQL进行记录在要使用的地方使用include标签进行引入。
声明
sql idempColumnseid,emp_name,age,sex,email/sql引用
!--ListEmp getEmpByCondition(Emp emp);--
select idgetEmpByCondition resultTypeEmpselect include refidempColumns/include from t_emp
/select