马果老师整理
在实际应用mybatis中的过程中,主要是采用代理的方式配置mybatis:
代理配置mybatis的特点:
- Dao层主要是编写接口,不需要编写实现类
- Dao接口的名称必须要与Mapper映射文件的名称一样,只是后缀名不同
- Mapper.xml文件的namespace必须是:Mapper接口的全路径
自动生成实体类和dao包接口和映射文件
用插件生成:
- 实体类
- Mapper接口
- Mapper映射文件
准备工作:
1、在mybatis网站中,下载一个插件包(jar)
- mybatis-generator-core-1.3.2.jar
- mysql-connector-java-3.1.10-bin.jar
2、准备一个用于生成代码的配置文件xml
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动,当前文件下驱动包的名称要和location对应-->
<classPathEntry location="驱动包名称"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mydb" userId="root" password="root">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型entity的包名和位置-->
<javaModelGenerator targetPackage="org.java.entity" targetProject="项目的路径地址\src">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="org.java.dao" targetProject="项目的路径地址\src">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="org.java.dao" targetProject="项目的路径地址\src">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<table tableName="inf" domainObjectName="Inf" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
</context>
</generatorConfiguration>
3、修改xml文件中的内容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动-->
<classPathEntry location="mysql-connector-java-3.1.10-bin.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mydb" userId="root" password="root">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型entity的包名和位置-->
<javaModelGenerator targetPackage="org.java.entity" targetProject="D:\space\eclipseSpace\j54\spring_j54_9_1\src">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="org.java.dao" targetProject="D:\space\eclipseSpace\j54\spring_j54_9_1\src">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="org.java.dao" targetProject="D:\space\eclipseSpace\j54\spring_j54_9_1\src">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<table tableName="inf" domainObjectName="Inf" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
</context>
</generatorConfiguration>
4、在cmd模式下,进入插件所在目录,执行下列命令:
- win+r,进入cmd
- 进入插件所放的目录,我的在E:\mysql
- 执行java -jar mybatis-generator-core-1.3.2.jar -configfile generatorConfig.xml -overwrite
如果需要生成当前数据库里的所有表,则:
<!-- 要生成的所有表 tableName里面写% 去掉domainObjectName-->
<table tableName="%" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
自动生成Oracle数据库里的表
只需改变generatorConfig.xml里的值
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动-->
<classPathEntry location="ojdbc6.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@localhost:1521:XE" userId="d91" password="d91">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型entity的包名和位置-->
<javaModelGenerator targetPackage="org.java.entity" targetProject="D:\space\eclipseSpace\j54\spring_j54_9_1\src">
<!-- 关闭启用子包名称-->
<property name="enableSubPackages" value="false"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="org.java.dao" targetProject="D:\space\eclipseSpace\j54\spring_j54_9_1\src">
<!-- 关闭启用子包名称-->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="org.java.dao" targetProject="D:\space\eclipseSpace\j54\spring_j54_9_1\src">
<!-- 关闭启用子包名称-->
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!-- 要生成的表 tableName为%表示生成所有表,schema表示生成d91用户下的表-->
<table tableName="%" schema="d91" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
</context>
</generatorConfiguration>
数据库中的表,如果存在一定关联,通过mybatis进行映射以后,它们会产生关联关系:
1对1 ------------one to one
人员与身份证
1对多 ------------one to many
省份与城市
多对1 ------------many to one
城市与省份
多对多 -----------many to many
学生与老师
============================================================
1对多,多对1
如果数据库的两张表之间,存在主外键关系,映射以后,它们就会存在一对多以及多对一的关系
Province类(一)
pid
pname
//映射成实体类以后,一的一方,由于主外键关联,将会产生一个关联属性
private List<City> = new ArrayList<City>();
package org.java.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
//1
public class Province implements Serializable {
private Integer pid;
private String pname;
//一的一方,产生集合类型的关联属性
private List<City> cities = new ArrayList<>();
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public List<City> getCities() {
return cities;
}
public void setCities(List<City> cities) {
this.cities = cities;
}
}
----------------------------------------------
City类 (多)
cid
cname
private Province province;----它是外键pid,它映射以后,将会变为主键表所对应的实体类
package org.java.entity;
import java.io.Serializable;
public class City implements Serializable {
private Integer cid;
private String cname;
private Province province;//关联属性(由外键产生)
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Province getProvince() {
return province;
}
public void setProvince(Province province) {
this.province = province;
}
}
示例
CityMapper.java
package org.java.dao;
import org.java.entity.City;
public interface CityMapper {
public City findByCid(Integer cid);
}
CityMapper.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 namespace="org.java.dao.CityMapper">
<select id="findProvinceByPid" parameterType="int" resultType="province">
select * from province where pid=#{pid}
</select>
<resultMap id="cityMap" type="city">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<association property="province" column="pid" select="findProvinceByPid"/>
</resultMap>
<select id="findByCid" parameterType="int" resultMap="cityMap">
select cid,cname,pid from city where cid=#{cid}
</select>
</mapper>
测试
package org.java;
import org.apache.ibatis.session.SqlSession;
import org.java.dao.CityMapper;
import org.java.entity.City;
import org.java.util.MyBatisUtil;
import org.junit.Test;
public class CityService {
@Test
public void findByCid(){
SqlSession ses = MyBatisUtil.getSession();
CityMapper mapper = ses.getMapper(CityMapper.class);
City city = mapper.findByCid(3);
System.out.println("城市编号:"+city.getCid());
System.out.println("城市名称:"+city.getCname());
System.out.println("所属省份名称:"+city.getProvince().getPname());
ses.close();
}
}
mybatis中 resultMap与resultType的区别:
- resultType:自动封装返回类型,但这种方式不能加载关联属性的数据
- resultMap: 手动封装返回类型,这种可以加载关联属性
懒加载
默认情况下:在mybatis中,如果配置了关联查询,在查询一个对象,将会自动查询与它相关的关联属性
分析:假设,有一个主贴,这一个主贴有1万个回贴
- 如果配置了默认加载方式,只要一查询主贴,这1万个回贴都会加载到内存中
mybatis中,有一种延迟加载机制:(懒加载) lazy
一开始查询时,只加载数据表中有字段对应的属性,关联属性一开始并不加载,关联属性什么时候用,什么时候
加载
配置延迟加载后:类中的关联属性,什么用,什么时候才会关联表
配置懒加载
在mybatis-config.xml中的properties属性下面进行配置
<!--相关配置-->
<settings>
<!--启用延迟加载机制-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--不使用积极加载(什么时候使用关联属性,什么时候查询关联表)-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
使用mybatis加载关联属性的方式有两种:
方式1: 进行二次查询
- 一般如果使用二次查询加载关联属性,都建议采用延迟加载
方式2:采用联表查询,只查询一次
一对一,多对一的联表查询
<resultMap id="cityMap" type="city">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<association property="province" javaType="province">
<id property="pid" column="pid"/>
<result property="pname" column="pname"/>
</association>
</resultMap>
一对多,多对多的联表查询
<resultMap id="provinceMap" type="province">
<id property="pid" column="pid"/>
<result property="pname" column="pname"/>
<!--配置关联属性-->
<collection property="cities" ofType="city">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
</collection>
</resultMap>
<select id="findProvinceByPid" parameterType="int" resultMap="provinceMap">
SELECT c.cid,c.cname,p.pid,p.pname FROM city c,province p WHERE c.pid=p.pid AND p.pid=#{pid}
</select>
联表查询时:
- 多对一,一对一的关联属性,使用:javaType
- 一对多,多对多的关联属性,使用:ofType
----------------------------------------------------------------------------------
一对一,多对多
一对一的配置: 人员与身份证
- 如果是一对一的关系: 在实体类中将会产生一个关联属性,类型为关联表所映射以后的实体类型
示例:
IdCard.java
package org.java.entity;
import java.io.Serializable;
public class IdCard implements Serializable {
private Integer cid;//编号
private String cno;//证件号码
//关联属性
private Person person;
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCno() {
return cno;
}
public void setCno(String cno) {
this.cno = cno;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
Person.java
package org.java.entity;
import java.io.Serializable;
public class Person implements Serializable {
private Integer pid;//人员编号
private String pname;//人员名称
//关联属性
private IdCard idCard;
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
}
PersonMapper.java
package org.java.dao;
import org.java.entity.Person;
public interface PersonMapper {
public Person findPerson(int pid);
}
PersonMapper.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 namespace="org.java.dao.PersonMapper">
<resultMap id="personMap" type="person">
<id property="pid" column="pid"/>
<result property="pname" column="pname"/>
<association property="idCard" javaType="idCard">
<id property="cid" column="cid"/>
<result property="cno" column="cno"/>
</association>
</resultMap>
<select id="findPerson" parameterType="int" resultMap="personMap">
SELECT p.pid,p.pname,c.cid,c.cno FROM person p LEFT OUTER JOIN idCard c ON(p.pid=c.cid) WHERE p.pid=#{pid}
</select>
</mapper>
测试:
package org.java.service;
import org.apache.ibatis.session.SqlSession;
import org.java.dao.PersonMapper;
import org.java.entity.IdCard;
import org.java.entity.Person;
import org.java.util.MyBatisUtil;
import org.junit.Test;
public class PersonService {
@Test
public void findPerson(){
SqlSession ses = MyBatisUtil.getSession();
PersonMapper mapper=ses.getMapper(PersonMapper.class);
Person person = mapper.findPerson(3);
System.out.println("姓名:"+person.getPname());
IdCard idCard = person.getIdCard();
if(idCard==null){
System.out.println("该用户暂无证件");
}else{
System.out.println("身份证号:"+idCard.getCno());
}
ses.close();
}
}
多对多: many-to-many
- 老师与学生, 开发人员与项目组
- 多对多的本质:其实就是两个一对多,站在谁的角度看,自己就是一,对方就是多
测试数据:
CREATE TABLE teacher
(
tid INT PRIMARY KEY,#老师编号,
tname VARCHAR(20)#老师名称
)
INSERT INTO teacher VALUES(1,'张老师');
INSERT INTO teacher VALUES(2,'李老师');
CREATE TABLE stu
(
sid INT PRIMARY KEY,#学生编号
sname VARCHAR(20)#学生名称
)
INSERT INTO stu VALUES(1,'张三');
INSERT INTO stu VALUES(2,'李四');
##老师与学生的关系表
CREATE TABLE teacher_stu
(
tid INT,#代表老师的编号
sid INT #代表学生的编号
)
INSERT INTO teacher_stu VALUES(1,1);
INSERT INTO teacher_stu VALUES(1,2);
INSERT INTO teacher_stu VALUES(2,1);
INSERT INTO teacher_stu VALUES(2,2);
SELECT * FROM teacher_stu;
SELECT a.tid,a.tname,b.sid,b.sname FROM teacher a,stu b,teacher_stu c
WHERE a.tid = c.tid AND b.sid = c.sid AND a.tid=2;
Stu.java
package org.java.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Stu implements Serializable {
private Integer sid;//学生编号
private String sname;//学生姓名
//关联属性
private List<Teacher> teachers = new ArrayList<>();
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public List<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(List<Teacher> teachers) {
this.teachers = teachers;
}
}
Teacher.java
package org.java.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Teacher implements Serializable {
private Integer tid;//老师编号
private String tname;//老师名称
//关联属性
private List<Stu> stus = new ArrayList<>();
public Integer getTid() {
return tid;
}
public void setTid(Integer tid) {
this.tid = tid;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
public List<Stu> getStus() {
return stus;
}
public void setStus(List<Stu> stus) {
this.stus = stus;
}
}
TeacherMapper.java
package org.java.dao;
import org.java.entity.Teacher;
public interface TeacherMapper {
public Teacher findTeacherByTid(int tid);
}
TeacherMapper.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 namespace="org.java.dao.TeacherMapper">
<resultMap id="teacherMap" type="teacher">
<id property="tid" column="tid"/>
<result property="tname" column="tname"/>
<collection property="stus" ofType="stu">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
</collection>
</resultMap>
<select id="findTeacherByTid" parameterType="int" resultMap="teacherMap">
SELECT a.tid,a.tname,b.sid,b.sname FROM teacher a,stu b,teacher_stu c
WHERE a.tid = c.tid AND b.sid = c.sid AND a.tid=#{tid}
</select>
</mapper>
测试:
package org.java.service;
import org.apache.ibatis.session.SqlSession;
import org.java.dao.TeacherMapper;
import org.java.entity.Stu;
import org.java.entity.Teacher;
import org.java.util.MyBatisUtil;
import org.junit.Test;
import java.util.List;
public class TeacherService {
@Test
public void findTeacher(){
SqlSession ses = MyBatisUtil.getSession();
TeacherMapper mapper = ses.getMapper(TeacherMapper.class);
Teacher teacher = mapper.findTeacherByTid(2);
System.out.println("老师名称:"+teacher.getTname());
System.out.println("-----------------");
List<Stu> stus = teacher.getStus();
for(Stu s:stus){
System.out.println(s.getSname());
}
ses.close();
}
}
多对多的关联,不需要在数据表中用主外键描述,而是通过一张单独的关系表来描述,双方的关联