一、Dao代理
-
前提:使用MyBatis进行Dao接口实现类开发时,几乎所有方法内部实现方式都是一致的
-
public 返回类型 方法名(参数1,参数2){
SqlSession sqlSession = SqlSessionUtil.openSession();
结果 = sqlSession.方法(“sql语句”);
sqlSession.close();
}
-
-
Dao代理:
-
Dao代理是MyBatis框架提供的一个功能;
-
Dao代理服务下,开发人员只需要开发Dao接口和SQL语句;
-
Dao代理服务下,由MyBatis框架负责在内存中生成Dao接口实现类,并创建实现类的实例对象。
-
-
为了获得Dao代理服务,需要遵守的规则:
-
SQL映射文件名必须与对应的Dao接口的名称保持一致。
-
DeptDao.class DeptDao.xml
-
-
SQL映射文件必须与对应的Dao接口存储在同一个包下。
-
dao.(DeptDao.class) dao.(DeptDao.xml)
-
-
SQL映射文件中namespace属性的值必须是对应的Dao接口的全限定名称
<Mapper namespace = “com.pm.dao.DeptDao.class">
</Mapper>
-
SQL映射文件中SQL语句的id编号必须与对应的Dao接口中的方法名相同
<Mapper namespace = “com.pm.dao.DeptDao.class">
<insert id = "insertDept"></insert>
</Mapper>
-
public interface DeptDao {
public int addDept(Dept dept);
public int delDept(int deptNo);
}
<mapper namespace="com.pm.dao.DeptDao">
<insert id="addDept" parameterType="dept">
insert into dept values(#{deptNo},#{dname},#{loc})
</insert>
<delete id="delDept" parameterType="int">
delete from dept where deptNo=#{deptNo}
</delete>
</mapper>
-
在遵守了对应规则之后,如何获得需要服务
-
DeptDao dao = sqlSession.getMapper(DeptDao.class);//返回由MyBatis提供的Dao接口实现类的实例对象,dao.方法()来推送SQL
-
@Test
public void test1()throws Exception{
SqlSession sqlSession = SqlSessionUtil.openSession(true);
//向MyBatis索要DeptDao接口的实例对象
DeptDao dao = sqlSession.getMapper(DeptDao.class);
//使用实例对象调用方法推送Sql语句
dao.delDept(50);
sqlSession.close();
}
-
遇见的常见异常
-
Cause: java.io.IOException: Could not find resource com/pm/dao/DeptDao.xml
-
原因:Maven项目运行时路径在[target],MyBatis在以target文件夹作为起始编译位置来定位资源文件,resources下文件夹会被Maven工具直接放置在target/classes下面,但是Maven项目其他文件夹下配置文件并不会放置到target/classes下面
-
解决:将指定文件夹位置通知Maven,这样将Maven指定文件下配置文件放置到target/classes中
-
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
二、MyBatis中配置设置
-
每一个在包
com.pm.entity
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如com.pm.entity.dept
的别名为dept
。
<!--类型别名标签-->
<typeAliases>
<package name="com.pm.entity"/>
</typeAliases>
-
指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
<!--日志输出-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
注意:配置文件标签有顺序,需按照顺序进行配置。
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--配置-->
<properties/><!--属性-->
<settings/><!--设置-->
<typeAliases/><!--类型别名-->
<typeHandlers/><!--类型处理器-->
<objectFactory/><!--对象工厂-->
<plugins/><!--插件-->
<environments><!--配置环境-->
<environment><!--环境变量-->
<transactionManager/><!--事务管理器-->
<dataSource/><!--数据源-->
</environment>
</environments>
<databaseidProvider/><!--数据库厂商标识-->
<mappers/><!--映射器-->
</configuration>
-
统一配置数据库链接信息
-
config.properties
-
myDriver=com.mysql.jdbc.Driver
myUrl=jdbc:mysql://localhost:3306/test
user=root
pwd=****
-
mybatis.xml
<environment id="one">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${myDriver}"/>
<property name="url" value="${myUrl}"/>
<property name="username" value="${user}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
三、动态SQL
-
什么是动态SQL:
-
根据用户实际给出的条件来设置SQL语句的结构;
-
-
动态SQL之<if>
<!--if标签使用-->
<!--
> 大于
< 小于
-->
<select id="find_1" parameterType="emp" resultType="emp">
select * from emp
where 1=1
<if test="job !=null and job !=''">
and job=#{job}
</if>
<if test="sal !=0 and sal !=null">
and sal > #{sal}
</if>
</select>
@Test
public void test1()throws Exception{
SqlSession sqlSession = SqlSessionUtil.openSession(true);
EmpDao empDao = sqlSession.getMapper(EmpDao.class);
//设置请求参数
Emp emp = new Emp();// job==null sal==null
emp.setJob("salesman");
emp.setSal(1500.00);
List<Emp> empList = empDao.find_1(emp);
for(Emp obj:empList){
System.out.println(obj.toString());
}
}
-
动态SQL之<where>
<!--where标签使用-->
<select id="find_1" parameterType="emp" resultType="emp">
select * from emp
<where>
<if test="job !=null and job !=''">
and job=#{job}
</if>
<if test="sal !=0 and sal !=null">
and sal > #{sal}
</if>
</where>
</select>
@Test
public void test2()throws Exception{
SqlSession sqlSession = SqlSessionUtil.openSession(true);
EmpDao empDao = sqlSession.getMapper(EmpDao.class);
//设置请求参数
Emp emp = new Emp();// job==null sal==null
emp.setSal(2000.00);
List<Emp> empList = empDao.find_2(emp);
for(Emp obj:empList){
System.out.println(obj.toString());
}
}
-
动态SQL之<foreach>
-
<foreach/>标签用于实现对数组与集合的遍历。对其使用,需要注意:
-
collection表示要遍历的集合类型 表示要遍历的集合类型 表示要遍历的集合类型 表示要遍历的集合类型 , list ,array等。
-
open、close、separator为对遍历内容的 为对遍历内容的 为对遍历内容的 为对遍历内容的 SQL拼接。 拼接。
-
语法:
<foreach collection="集合类型"
open="开始的字符"
close="结束的字符"
item="集合中的成员"
separator="集合成员之间的分隔符">
#{item的值}
</foreach>
-
<!--
批处理添加,使用list集合存入若干个职员信息,
然后借助于foreach标签将职员信息作为数据行添加insert语句中,最终生成
insert into emp (empno,ename)values (),(),()......
-->
<insert id = "insert_Batch">
insert into emp(empno,ename)
values
<foreach collection="list" item="emp" separator",">
(#{emp.empNo},#{emp.ename})
</foreach>
</insert>
@Test
public void test3()throws Exception{
SqlSession sqlSession = SqlSessionUtil.openSession(true);
EmpDao empDao = sqlSession.getMapper(EmpDao.class);
//设置需要插入的职员信息
List empList = new ArrayList();
for(int i = 10000;i<=10002;i++){
Emp emp = new Emp();
emp.setEmpNo(i);
emp.setEname("emp_"+i);
empList.add(emp);
}
//通过Dao推送批处理添加语句
int result = empDao.insert_Batch(List empList);
sqlSession.close();
System.out.println("本次添加职员人数"+result);
}
四、多对一查询实现(基本没有用,略看)
-
介绍:查询多方数据时,将多方数据关联的一方数据一并查询出来
-
例子:查询职员编号为9527的职员信息以及职员所在部门的信息
select emp.* ,dept .*
from dept join emp
on dept.deptno=emp.deptno
where emp.deptno=9527
-
具体步骤实现:
-
第一步:在多方实体类添加一个属性,这个属性类型是一方实体类类型
-
第二步:在SQL映射文件中,配置查询结果映射关系
-
<select id="findByEmpNo" resultMap="emp_dept">
select emp.*,dept.*
from dept join emp
on dept.deptno = emp.deptno
where emp.empno=#{empNo}
</select>
<!--针对多对一设置映射关系-->
<resultMap id="emp_dept" type="emp">
<id column="empno" property="empNo"/>
<result column="ename" property="ename"/>
<result column="job" property="job"/>
<result column="hireDate" property="hireDate"/>
<result column="sal" property="sal"/>
<association property="dept" javaType="dept" column="deptNo">
<id column="deptNo" property="deptNo"/>
<result column="dname" property="dname"/>
<result column="loc" property="loc"/>
</association>
</resultMap>
@Test
public void test1()throws Exception{
SqlSession sqlSession = SqlSessionUtil.openSession(true);
EmpDao empDao = sqlSession.getMapper(EmpDao.class);
Emp emp = empDao.findByEmpNo(7566);
System.out.println("职员基本信息 "+emp.toString());
System.out.println("隶属部门信息 "+emp.getDept().toString());
sqlSession.close();
}
**注意:join连接合并规则** **1、连接合并方案生产临时表【字段个数】=一方表.字段个数+多方表.字段个数** **2、连接合并方案生产临时表【字段名称】=原始表名.字段名;避免出现同名字段** **3、连接合并方案生产临时表【数据行数】=一方表.总行数 * 多方表.总行数** **4、连接合并方案生产临时表【书记行拼接规则】:使用一方表每一个数据行与多方表所有的数据行拼接成全新的数据行** **5、连接合并方案生产临时表中逼人存在【脏数据行】,因此将临时表交给六个查询命令之前。必须将【合法数据行】过滤**
内连接过滤方案命令格式 from 一方表 join 多方表 on 合法数据行定位条件(关系表达式/逻辑表达式/特殊运算符---不能使用聚合行数 内连接过滤工作原理: on 工作原理与where一致,on循环遍历临时表每一个数据行。每次只能得到一行数据。 如果这行数据满足合法数据行特征就会被on存入到全新临时表 on 生成的临时表存放一定都是合法数据行 如何判断数据行是否是合法数据行: 情况1:若多方表声明【外键字段】,此时根据如下条件判断 on 当前数据行来自于一方表.主键值 = 当前数据行来自于多方表.主键值 情况2:若多方表没有声明【外键字段】,此时根据现实生活中存在隶属关系判断 on 现实生活中真实隶属关系
五、一对多查询实现(基本没有用,略看)
-
介绍:查询某个一方表中数据行信息时将其关联的所有多方信息检索出来
-
例子:查询某个部门详细信息以及部门下职员信息
select dept.* , emp.*
from dept jion emp
on dept.deptno=emp.deptno
where dept.depno=9527
-
步骤:
-
第一步:在一方表对应的实体类中添加一个属性。
这个属性类型应该是List,list存放与多方表对应的实体类对象,表示当前一方对象拥有的所有多方对象
-
第二步:在SQL映射文件中,配置查询结果映射关系
-
<!--根据主键值查询部门信息-->
<select id="findDeptById" resultMap="dept_emp">
select * from dept where deptno=#{deptno}
</select>
<!--设置部门查询生成临时表与Dept类之间映射关系-->
<resultMap id="dept_emp" type="dept">
<id column="DEPTNO" property="deptNo"/>
<result column="DNAME" property="dname"/>
<result column="LOC" property="loc"/>
<collection property="empList" ofType="emp" column="DEPTNO" select="findEmpByDeptNo"/>
</resultMap>
<select id="findEmpByDeptNo" resultType="emp">
select * from emp where deptno=#{deptno}
</select>
@Test
public void test1()throws Exception{
SqlSession sqlSession = SqlSessionUtil.openSession(true);
DeptDao dao = sqlSession.getMapper(DeptDao.class);
Dept dept = dao.findDeptById(10);
System.out.println("部门基本信息 "+dept.toString());
System.out.println("部门下职员信息 "+dept.getEmpList());
sqlSession.close();
}
六、MyBatis缓存机制(基本没用,略看),因为没有一个表是不更新的。
-
SqlSession对象存在一个集合,用于存储sqlSession推送查询返回数据
-
好处就是SqlSession接收到相同的查询语句推送命令时,此时避免推送查询语句,直接从sqlSession对象中集合中得到需要数据,从而提升查询效率。