前言:

  百度百科:

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可    以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

  这篇文章讲解如何 使用mysql数据库,总结mybatis的一对一、一对多、多对多映射如何进行增删改查。


准备工作:

  1.打开ecplise创建一个普通的java项目。项目结构如下图所示:

  2.先看jar包,这次我们用到4个jar包,单元测试jar包junit-4.7.jar,日志包log4j-1.2.17.jar,mybatis所用的jar包以及连接mysql数据库用到的mysql-connector-java-5.1.47.jar

【ojdbc14.jar是连接oracle数据库用到的jar包】。

  注:jar包记得build path

  3.dtd约束文件:是对全局配置文件和sql映射文件的约束。在ecplise中点击 window --> preference ,在输入栏键入xml,然后选择 XML Catalog,点击Add。

 

  注:-//mybatis.org//DTD Mapper 3.0//EN  、-//mybatis.org//DTD Config 3.0//EN ,key值是规定的,location是点击workspace在项目中选择的约束文件。

  4.driver.properties配置文件是连接数据库所用到的配置信息。在mybaits-config.xml中会用到。

#基于mysql数据库
driver=com.mysql.jdbc.Driver
#?useUnicode=true&characterEncoding=utf8为了支持中文数据的写入
url=jdbc:mysql://188.131.246.182:3306/cnblogs?useUnicode=true&characterEncoding=utf-8
username=study
password=123456 #基于Oracle数据库
#driver=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin:@127.0.0.1:1521:XE
#username=briup
#password=briup

  5.log4j.properties是日志jar包要用到的配置文件。其中定义了输出日志级别、输出位置以及是否打印sql语句。

log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %c - %m%n
#show sql
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

  6.全局配置文件:mybatis-config.xml。该文件的详细信息可网上找资料。我这里给一个简单能用的。

<?xml version="1.0" encoding="UTF-8"?>
<!-- dtd约束 -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd" >
<configuration>
<!-- properties必须是第一个子标签
定义变量,定义完成后,可以在后面的标签中使用
resource引入配置文件,优先级更高
-->
<properties resource="driver.properties">
<property name="driver" value=""/>
<property name="url" value=""/>
<property name="username" value=""/>
<property name="password" value=""/>
</properties> <typeAliases>
     <!-- 给包下的类定义别名 -->
<package name="com.cnblogs.bean"/>
</typeAliases> <!-- 使用mysql数据库,如果要切换到Oracle数据库,default="oracle" -->
<environments default="mysql">
<!-- mysql -->
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment> <!-- oracle -->
<environment id="oracle">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/cnblogs/OneToMany/OneToMany.xml" />
</mappers> </configuration>

  

  准备工作完成以后就可以开始写sql语句了。


   注:嵌套结果查询:一次查一张表,分多次查。

      嵌套结果映射:一次查多张表,分别映射。                  

                  一对一映射

1.创建bean类:Student【学生】、FoodCard【饭卡】

  Student.java

package com.cnblogs.bean;
/**
* 和饭卡一一对应
* CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`gender` varchar(255) NOT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
)
*
*/
public class Student { private Integer id; private String name; private String gender; private int age; public Student() {
super();
// TODO Auto-generated constructor stub
} public Student(String name, String gender, int age) {
super();
this.name = name;
this.gender = gender;
this.age = age;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", gender=" + gender +
", age=" + age + "]";
} }

  FoodCard.java

package com.cnblogs.bean;
/**
* 饭卡,和学生一对一映射
* CREATE TABLE `food_card` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`number` varchar(255) NOT NULL,
`balance` double DEFAULT NULL,
`stu_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `stu_id` (`stu_id`),
CONSTRAINT `stu_id` FOREIGN KEY (`stu_id`) REFERENCES `student` (`id`)
)
*
*/
public class FoodCard {
private Integer id; // 卡号
private String number; //余额
private Double balance; // 对应的学生
private Student stu; public FoodCard() {
super();
// TODO Auto-generated constructor stub
} public FoodCard(String number, Double balance) {
super();
this.number = number;
this.balance = balance;
} public FoodCard(String number, Double balance, Student stu) {
super();
this.number = number;
this.balance = balance;
this.stu = stu;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getNumber() {
return number;
} public void setNumber(String number) {
this.number = number;
} public Double getBalance() {
return balance;
} public void setBalance(Double balance) {
this.balance = balance;
} public Student getStu() {
return stu;
} public void setStu(Student stu) {
this.stu = stu;
} @Override
public String toString() {
return "FoodCard [id=" + id + ", number=" + number + ", balance=" +
balance + ", stu=" + stu + "]";
} }

3.编写sql映射文件。首先告诉mybatis那个xml文件是你的映射文件。在mybatis的<Mappers>标签中添加一条

" <mapper resource="com/cnblogs/oneToOne/OneToOne.xml"/> " 按住Ctrl+鼠标左键点击跳转到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">
<!-- com.cnblogs.oneToOne.OneToOne是我们定义接口的全限定名字 这样就可以使用接口调用映射的SQL语句了 这个
名字一定要和接口对应上-->
<mapper namespace="com.cnblogs.oneToOne.OneToOne"> <!-- 插入一条学生信息 -->
<insert id="insertStudent" parameterType="Student" useGeneratedKeys="true"
keyProperty="id">
insert into student(name,gender,age)
values(#{name},#{gender},#{age})
</insert> <!-- 插入一条饭卡信息 自动生成主键
#{number}代表调用getNumber()方法
-->
<insert id="insertFoodCard" parameterType="FoodCard" useGeneratedKeys="true"
keyProperty="id">
insert into food_card(number,balance,stu_id)
values(#{number},#{balance},#{stu.id})
</insert> <!-- 删除一条饭卡信息-->
<delete id="deleteFoodCardById" parameterType="int">
delete from food_card where id=#{id}
</delete> <!-- 根据学生id删除一条饭卡信息 -->
<delete id="deleteFoodCardByStuId" parameterType="int">
delete from food_card where stu_id=#{id}
</delete>
<!-- 删除一条学生信息 由于主键被饭卡表引用,需要级联删除,先调用deleteFoodCardByStuId -->
<delete id="deleteStudentById" parameterType="int">
delete from student where id=#{id}
</delete> <!-- 模拟一个业务需求:假设一批学生毕业了,需要删除关于这批学生的所有饭卡信息 -->
<delete id="deleteFoodCardByStuIds" parameterType="java.util.List">
delete from food_card where stu_id in(
<foreach collection="list" item="stu" separator="," >
#{stu.id}
</foreach>
)
</delete> <!-- 如果方法要传入两个参数,#{param1}代表第一个参数,#{param2}代表第二个参数 -->
<!-- 根据名字和年龄更改一条学生记录 -->
<update id="updateStudentByNameAndAge">
update student set age=21
where name=#{param1} and age=#{param2}
</update> <!-- 一对一映射
查询两张表food_card和student,如何将student查到的记录映射到
FoodCard对象中?
-->
<resultMap type="Student" id="StudentMap">
<id column="id" property="id" />
<result column="name" property="name"/>
<result column="gender" property="gender"/>
<result column="age" property="age"/>
</resultMap> <!-- 嵌套结果映射 -->
<resultMap type="FoodCard" id="FoodCardMap">
<id column="id" property="id" />
<result column="number" property="number"/>
<result column="balance" property="balance"/>
<!-- 一对一映射,将很多列映射到stu属性上 -->
<association property="stu" resultMap="StudentMap" />
</resultMap> <select id="selectFoodCardWithStudent" parameterType="int" resultMap="FoodCardMap">
select * from student stu,food_card fc
where fc.id=#{id} and fc.stu_id=stu.id
</select> <!-- 嵌套结果查询 -->
<select id="selectStudentById" resultType="Student">
select * from student where id=#{id}
</select>
<resultMap type="FoodCard" id="FoodCardMap2">
<id column="id" property="id" />
<result column="number" property="number"/>
<result column="balance" property="balance"/>
<!-- 一对一 嵌套结果查询-->
<association property="stu" select="selectStudentById" column="stu_id"/>
</resultMap>
<select id="selectFoodCardWithStudent2" parameterType="int" resultMap="FoodCardMap2">
select * from food_card fc where fc.id=#{id}
</select> </mapper>

      *嵌套结果映射:

  <!-- 嵌套结果映射 -->

<resultMap type="FoodCard" id="FoodCardMap">

  <id column="id" property="id" />

  <result column="number" property="number"/>

  <result column="balance" property="balance"/>

   <!-- 一对一映射,将很多列映射到stu属性上 -->

  <association property="stu" resultMap="StudentMap" />

</resultMap>

<select id="selectFoodCardWithStudent" parameterType="int" resultMap="FoodCardMap">

  select * from student stu,food_card fc where fc.id=#{id} and fc.stu_id=stu.id

</select>

  

  resultMap标签,type属性表示和那种类型对应,id值起唯一标识作用,主键用id标签,表的其它列用result标签,column代表和数据库表对应的列,property

表示type值对应的属性【property指getXXX和setXXX】,column和property组合起来表示把查到的记录对应的列映射到对应的属性上。

  嵌套结果查询的SQL语句,返回值不能再用resultType指定了,用resultMap指定。

注:嵌套结果映射中,如果两个表有同名的列,自然链接的时候只会保留一个列,上述中如果直接 'select * ' 会导致饭卡id和学生id一致。

必须显式的指定返回的列, ' select fc.id,fc.number,fc.balance,fc.stu_id,stu.id,stu.name,stu.age,stu.gender

from student stu,food_card fc where fc.id=#{id} and fc.stu_id=stu.id'。嵌套结果查询不需要显式指定。

  

    *嵌套结果查询

<!-- 嵌套结果查询 -->
<select id="selectStudentById" resultType="Student">
select * from student where id=#{id}
</select>
<resultMap type="FoodCard" id="FoodCardMap2">
<id column="id" property="id" />
<result column="number" property="number"/>
<result column="balance" property="balance"/>
<!-- 一对一 嵌套结果查询-->
<association property="stu" select="selectStudentById" column="stu_id"/>
</resultMap>
<select id="selectFoodCardWithStudent2" parameterType="int" resultMap="FoodCardMap2">
select * from food_card fc where fc.id=#{id}
</select>
  
  一次查一张表,多次查。<association property="stu" select="selectStudentById" column="stu_id"/>
property代表映射到那个属性,select代表调用那个方法,column指定当前查表返回的那个列作为方法的参数。如果
还需要再查一张表,按照规则再加一条<association>
 

    所有的sql语句对应的接口中必须有该方法。 

package com.cnblogs.oneToOne;

import java.util.List;

import com.cnblogs.bean.FoodCard;
import com.cnblogs.bean.Student; public interface OneToOne {
/**
* 插入一条饭卡信息
*/
public abstract void insertFoodCard(FoodCard foodCard); /**
* 插入一条学生信息
*/
public abstract void insertStudent(Student stu); /**
* 删除一条饭卡记录
*/
public abstract void deleteFoodCardById(Integer id); /**
* 根据学生id删除一条饭卡记录
*/
public abstract void deleteFoodCardByStuId(Integer id); /**
* 删除一条学生记录根据id
* 调用该方(法应该先调用deleteFoodCardByStuId(Integer)
*/
public abstract void deleteStudentById(Integer id); /**
* 提供一批学生信息,删除对应的饭卡
*/
public abstract void deleteFoodCardByStuIds(List<Student> stus); /**
* 根据年龄和姓名更改一条学生记录
*/
public abstract void updateStudentByNameAndAge(String name,Integer age); /**
* 根据id查找饭卡的详细信息[包括学生属性]
* 使用嵌套结果映射
*/
public abstract FoodCard selectFoodCardWithStudent(Integer id); /**
* 根据id查找学生记录
*/
public abstract Student selectStudentById(Integer id); /**
* 根据id查找饭卡的详细信息[包括学生属性]
* 使用嵌套结果查询
*/
public abstract FoodCard selectFoodCardWithStudent2(Integer id);
}

    单元测试类:

package com.cnblogs.jtest;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test; import com.cnblogs.bean.FoodCard;
import com.cnblogs.bean.Student;
import com.cnblogs.oneToOne.OneToOne;
import com.cnblogs.utils.MySqlSessionFactory; public class OneToOneTest { @Test
public void insertStudent() {
Student student1 = new Student("jack","男",20);
Student student2 = new Student("Tina", "女", 16); InputStream inputStream;
try{
// 读取配置文件
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
// 手动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(false); OneToOne mapper = sqlSession.getMapper(OneToOne.class);
mapper.insertStudent(student1);
mapper.insertStudent(student2); // 提交事务
sqlSession.commit(); } catch(Exception e) {
e.printStackTrace();
}
} @Test
public void insertFoodCard() {
Student stu1 = new Student();
stu1.setId(15);
Student stu2 = new Student();
stu2.setId(16); FoodCard foodCard1 = new FoodCard("123456",100.0,stu1);
FoodCard foodCard2 = new FoodCard("123457",312.4,stu2); InputStream inputStream;
try{
// 读取配置文件
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class);
mapper.insertFoodCard(foodCard1);
mapper.insertFoodCard(foodCard2); // 提交事务
sqlSession.commit(); } catch(Exception e) {
e.printStackTrace();
}
} @Test
public void deleteFoodCardById() {
InputStream inputStream;
try{
// 读取配置文件
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class);
mapper.deleteFoodCardById(5); // 提交事务
sqlSession.commit(); } catch(Exception e) {
e.printStackTrace();
}
} @Test
public void deleteStudentById() {
InputStream inputStream;
try{
// 读取配置文件
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class);
mapper.deleteFoodCardByStuId(6);
mapper.deleteStudentById(6);
// 提交事务
sqlSession.commit(); } catch(Exception e) {
e.printStackTrace();
}
} @Test
public void deleteFoodCardByStuIds() {
InputStream inputStream;
try{
// 读取配置文件
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class); Student stu1 = new Student();
stu1.setId(5);
Student stu2 = new Student();
stu2.setId(7);
Student stu3 = new Student();
stu3.setId(10);
ArrayList<Student> stus = new ArrayList<Student>();
stus.add(stu1);
stus.add(stu2);
stus.add(stu3); mapper.deleteFoodCardByStuIds(stus); // 提交事务
sqlSession.commit(); } catch(Exception e) {
e.printStackTrace();
}
} @SuppressWarnings("unused")
@Test
public void updateStudentByNameAndAge() {
SqlSession sqlSession = null;
try {
// 手动提交事务
sqlSession = MySqlSessionFactory.opensession();
OneToOne mapper = sqlSession.getMapper(OneToOne.class); mapper.updateStudentByNameAndAge("jack", 20); sqlSession.commit();
} catch (IOException e) {
if(sqlSession != null)
sqlSession.rollback();
e.printStackTrace();
}
} @Test
public void selectFoodCardWithStudent() {
SqlSession sqlSession = null;
try {
sqlSession = MySqlSessionFactory.opensession();
OneToOne mapper = sqlSession.getMapper(OneToOne.class); FoodCard foodCard = mapper.selectFoodCardWithStudent(12);
System.out.println(foodCard); } catch (IOException e) {
e.printStackTrace();
}
} @Test
public void selectFoodCardWithStudent2() {
SqlSession sqlSession = null;
try {
sqlSession = MySqlSessionFactory.opensession();
OneToOne mapper = sqlSession.getMapper(OneToOne.class); FoodCard foodCard = mapper.selectFoodCardWithStudent2(12);
System.out.println(foodCard); } catch (IOException e) {
e.printStackTrace();
}
}
}

    获得SqlSesion对象的步骤重多,我们可以进行封装成一个工厂类。

package com.cnblogs.utils;

import java.io.IOException;
import java.io.InputStream; import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MySqlSessionFactory {
    
    public static SqlSessionFactory getSqlSessionFactory() throws IOException{
        // 读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        if(inputStream == null)
            throw new IOException("配置文件路径不对或者配置文件内容出错");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;     }
    
    /**
     *
     * @param flag true 自动提交事务,false 手动提交事务
     * @return
     */
    public static SqlSession opensession(boolean flag) throws IOException{
        return getSqlSessionFactory().openSession(flag);
    }
    
    /**
     * 默认手动提交事务
     * @return
     */
    public static SqlSession opensession() throws IOException{
        return opensession(false);
    }
    
}

          一对多映射

简单模拟一下映射关系,一个人只能有一个户籍所在地,而一个户籍所在地可以对应许多人。把外键放在一的那边。

1)pojo类:

Human.java

package com.cnblogs.bean;

import java.util.Date;

/**
* create table human(
* id int,
* name varchar,
* gender varchar,
* age int,
* dob datetime,
* address_id int reference address(id)
* )
*
*/
public class Human {
private Integer id; private String name; private String gender; private Integer age; private Date dob;
// 人对应的地址
private Address address; public Human() {
super();
} public Human(String name, String gender, Integer age, Date dob) {
super();
this.name = name;
this.gender = gender;
this.age = age;
this.dob = dob;
} public Human(String name, String gender, Integer age, Date dob, Address address) {
super();
this.name = name;
this.gender = gender;
this.age = age;
this.dob = dob;
this.address = address;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public Date getDob() {
return dob;
} public void setDob(Date dob) {
this.dob = dob;
} public Address getAddress() {
return address;
} public void setAddress(Address address) {
this.address = address;
} @Override
public String toString() {
return "Human [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age +
", dob=" + dob + ", address=" + address + "]";
} }

Address.java

package com.cnblogs.bean;

import java.util.List;

/**
* table
* address(
* id int key,
* province varchar,
* city varchar,
* street varchar
* )
*
*/
public class Address {
private Integer id; private String province; private String city; private String street;
// 地址对应的人
private List<Human> humans; public Address() {
super();
} public Address(String province, String city, String street) {
super();
this.province = province;
this.city = city;
this.street = street;
} public Address(String province, String city, String street, List<Human> humans) {
super();
this.province = province;
this.city = city;
this.street = street;
this.humans = humans;
} public Address(Integer id, String province, String city, String street) {
super();
this.id = id;
this.province = province;
this.city = city;
this.street = street;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getProvince() {
return province;
} public void setProvince(String province) {
this.province = province;
} public String getCity() {
return city;
} public void setCity(String city) {
this.city = city;
} public String getStreet() {
return street;
} public void setStreet(String street) {
this.street = street;
} public List<Human> getHumans() {
return humans;
} public void setHumans(List<Human> humans) {
this.humans = humans;
} @Override
public String toString() {
return "Address [id=" + id + ", province=" + province + ", city=" + city +
", street=" + street + "]";
} }

2)在mybatis<Mappers>下加一条:<mapper resource="com/cnblogs/oneToMany/OneToMany.xml" />

3)编写OneToMany.xml和OneTomany.java接口

<?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">
<!-- com.cnblogs.OneToMany.OneToMany是我们定义接口的全限定名字 这样就可以使用接口调用映射的SQL语句了 这个
名字一定要和接口对应上-->
<mapper namespace="com.cnblogs.oneToMany.OneToMany">
<!-- 插入一条地址信息 -->
<insert id="insertAddress" parameterType="Address"
useGeneratedKeys="true" keyProperty="id">
insert into address(province,city,street)
values(#{province},#{city},#{street})
</insert> <!-- 插入一条人类信息 -->
<insert id="insertHuman" parameterType="Human"
useGeneratedKeys="true" keyProperty="id">
insert into human(name,gender,age,dob,address_id)
values(#{name},#{gender},#{age},#{dob},#{address.id})
</insert> <!-- 删改类似,省略.... --> <!-- 结果集映射
基础结果集,说明了如何从数据库加载对象
-->
<resultMap type="Address" id="addressBaseMap">
<id property="id" column="id" />
<result property="province" column="province"/>
<result property="city" column="city"/>
<result property="street" column="street"/>
</resultMap>
<resultMap type="Human" id="humanBaseMap">
<id property="id" column="id" />
<result property="name" column="name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="dob" column="dob"/>
</resultMap> <!-- 结果集映射
一个人对应一个户籍,所以这里还是一对一映射
继承基础结果集
-->
<!-- 嵌套结果映射
继承:namespace + id 完全限定名
-->
<resultMap type="Human" id="humanMap"
extends="com.cnblogs.oneToMany.OneToMany.humanBaseMap">
<!-- 避免human的id和address的id起冲突,sql语句会给列起别名,相应的这里也需要更改 -->
<id property="id" column="hid" />
<association property="address" resultMap="addressBaseMap"></association>
</resultMap>
<select id="selectHumanWithAddressById" parameterType="int" resultMap="humanMap">
select h.id hid,h.name,h.gender,h.age,h.dob,a.*
from human h,address a
where h.id=#{id} and h.address_id = a.id
</select> <!-- 一对多
一个户籍地对应多个人
-->
<!-- 嵌套结果映射 -->
<resultMap type="Address" id="AddressMap"
extends="com.cnblogs.oneToMany.OneToMany.addressBaseMap">
<!-- 避免human的id和address的id起冲突,sql语句会给列起别名,相应的这里也需要更改 -->
<id property="id" column="aid"/>
<!-- 一对多使用collection集合 -->
<collection property="humans" resultMap="humanBaseMap" />
</resultMap>
<!-- 嵌套结果映射sql语句 -->
<select id="selectAddressWithHumanById" parameterType="int" resultMap="AddressMap">
select a.id aid,a.province,a.city,a.street,h.*
from address a,human h
where a.id=#{id} and a.id=h.address_id
</select> <!-- 嵌套结果查询 -->
<!-- 嵌套结果查询中被用到的另一条sql语句 -->
<select id="selectHumanByAddressId" parameterType="int" resultMap="humanBaseMap">
select * from human
where address_id=#{id}
</select>
<!-- 结果集 -->
<resultMap type="Address" id="AddressMap2"
extends="com.cnblogs.oneToMany.OneToMany.addressBaseMap">
<!-- 把id传过去 -->
<collection property="humans" select="selectHumanByAddressId" column="id" />
</resultMap>
<!-- 嵌套结果查询sql语句 -->
<select id="selectAddressWithHumanById2" parameterType="int" resultMap="AddressMap2">
select * from address
where id=#{id}
</select> </mapper>

OneTOMany.java

package com.cnblogs.oneToMany;

import java.util.List;

import com.cnblogs.bean.Address;
import com.cnblogs.bean.Human; public interface OneToMany {
/**
* 插入一条地址信息
* @param address
*/
public abstract void insertAddress(Address address); /**
* 插入一条人类信息
* @param humam
*/
public abstract void insertHuman(Human humam); /**
* 根据id查询一条人类信息[包括户籍的详细信息]
* @param id
*/
public abstract Human selectHumanWithAddressById(Integer id); /**
* 嵌套结果映射
* 根据id查询一条户籍信息[包括户籍所在地人的信息]
* @param id
* @return
*/
public abstract Address selectAddressWithHumanById(Integer id); /**
* 根据户籍地id查找人
* @param id
* @return
*/
public abstract List<Human> selectHumanByAddressId(Integer id); /**
* 嵌套结果查询
* 根据id查询一条户籍信息[包括户籍所在地人的信息]
* @param id
* @return
*/
public abstract Address selectAddressWithHumanById2(Integer id);
}

4)测试类

package com.cnblogs.jtest;

import java.io.IOException;
import java.util.Date;
import java.util.List; import org.apache.ibatis.session.SqlSession;
import org.junit.Test; import com.cnblogs.bean.Address;
import com.cnblogs.bean.Human;
import com.cnblogs.oneToMany.OneToMany;
import com.cnblogs.utils.MySqlSessionFactory; public class OnetoManyTest { @Test
public void insertHumanAndAddress() {
try{
SqlSession sqlSession = MySqlSessionFactory.opensession();
OneToMany mapper = sqlSession.getMapper(OneToMany.class); // 准备数据
Address address1 = new Address("湖南", "张家界", "步行街");
Address address2 = new Address("湖南", "长沙", "步行街"); mapper.insertAddress(address1);
mapper.insertAddress(address2); //提交事务
sqlSession.commit(); } catch(Exception e) {
e.printStackTrace();
} } @SuppressWarnings("unused")
@Test
public void insertHuman() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
OneToMany mapper = session.getMapper(OneToMany.class);
// 准备数据
Address address1 = new Address();
address1.setId(3);
Address address2 = new Address();
address2.setId(4);
Human human1 = new Human("jack","男",22,new Date(),address1);
Human human2 = new Human("tom","男",20,new Date(),address2);
Human human3 = new Human("tina","女",22,new Date(),address1);
Human human4 = new Human("alias","女",18,new Date(),address1);
// 插入数据
mapper.insertHuman(human1);
mapper.insertHuman(human2);
mapper.insertHuman(human3);
mapper.insertHuman(human4);
// 提交事务
session.commit();
} catch (IOException e) {
if(session != null)
session.close();
e.printStackTrace();
}
} @SuppressWarnings("unused")
@Test
public void selectHumanWithAddressById() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
OneToMany mapper = session.getMapper(OneToMany.class); Human human1 = mapper.selectHumanWithAddressById(1);
Human human2 = mapper.selectHumanWithAddressById(3);
System.out.println("human: " + human1);
System.out.println("human: " + human2);
} catch (IOException e) {
if(session != null)
session.close();
e.printStackTrace();
}
} @SuppressWarnings("unused")
@Test
public void selectAddressWithHumanById() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
OneToMany mapper = session.getMapper(OneToMany.class); Address address1 = mapper.selectAddressWithHumanById(3);
Address address2 = mapper.selectAddressWithHumanById(4); System.out.println("address: " + address1);
List<Human> humans1 = address1.getHumans();
System.out.println("humans : ");
for(Human h : humans1)
System.out.println(h);
System.out.println("============================");
System.out.println("address: " + address2);
List<Human> humans2 = address2.getHumans();
System.out.println("humans : ");
for(Human h : humans2)
System.out.println(h);
} catch (IOException e) {
if(session != null)
session.close();
e.printStackTrace();
}
} @SuppressWarnings("unused")
@Test
public void selectAddressWithHumanById2() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
OneToMany mapper = session.getMapper(OneToMany.class); Address address1 = mapper.selectAddressWithHumanById2(3);
Address address2 = mapper.selectAddressWithHumanById2(4); System.out.println("address: " + address1);
List<Human> humans1 = address1.getHumans();
System.out.println("humans : ");
for(Human h : humans1)
System.out.println(h);
System.out.println("============================");
System.out.println("address: " + address2);
List<Human> humans2 = address2.getHumans();
System.out.println("humans : ");
for(Human h : humans2)
System.out.println(h);
} catch (IOException e) {
if(session != null)
session.close();
e.printStackTrace();
}
}
}

                多对多 

描述:一个老师可以讲多门课,一门课可以有多个老师教。

1)pojo类

Teacher.java

package com.cnblogs.bean;

import java.util.List;
/**
* 教师类
* 和课程对多多
*/
public class Teacher {
// 教师id
private Long id;
// 教师名称
private String name;
// 教师职称 讲师 高级讲师 教授
private String title;
// 教师讲授的课程
private List<Course> courses; public Teacher() {
super();
} public Teacher(String name, String title) {
super();
this.name = name;
this.title = title;
} public Teacher(String name, String title, List<Course> courses) {
super();
this.name = name;
this.title = title;
this.courses = courses;
} public Teacher(Long id, String name, String title, List<Course> courses) {
super();
this.id = id;
this.name = name;
this.title = title;
this.courses = courses;
} public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public List<Course> getCourses() {
return courses;
} public void setCourses(List<Course> courses) {
this.courses = courses;
} @Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + ", title=" + title + ", courses=" + courses + "]";
} }

Course.java

package com.cnblogs.bean;

import java.util.List;
/**
* 课程类
* 和教师多对多
*
*/
public class Course {
// 课程id
private Long id;
// 课程名称
private String name;
// 课程描述
private String description;
// 课程对应的老师
private List<Teacher> teachers; public Course() {
super();
} public Course(String name, String description) {
super();
this.name = name;
this.description = description;
} public Course(String name, String description, List<Teacher> teachers) {
super();
this.name = name;
this.description = description;
this.teachers = teachers;
} public Course(Long id, String name, String description, List<Teacher> teachers) {
super();
this.id = id;
this.name = name;
this.description = description;
this.teachers = teachers;
} public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
} public List<Teacher> getTeachers() {
return teachers;
} public void setTeachers(List<Teacher> teachers) {
this.teachers = teachers;
} @Override
public String toString() {
return "Course [id=" + id + ", name=" + name + ", description=" + description + "]";
} }

桥表类:TeacherCourse.java

package com.cnblogs.bean;

import java.util.Date;

/**
* 桥表类
* 连接教师类和课程类
*
*/
public class TeacherCourse {
// id
private Long id;
// 授课开始时间
private Date begin;
// 授课结束时间
private Date end;
// 教师
private Teacher teacher;
// 课程
private Course course; public TeacherCourse() {
super();
// TODO Auto-generated constructor stub
} public TeacherCourse(Date begin, Date end) {
super();
this.begin = begin;
this.end = end;
} public TeacherCourse(Date begin, Date end, Teacher teacher, Course course) {
super();
this.begin = begin;
this.end = end;
this.teacher = teacher;
this.course = course;
} public TeacherCourse(Long id, Date begin, Date end, Teacher teacher, Course course) {
super();
this.id = id;
this.begin = begin;
this.end = end;
this.teacher = teacher;
this.course = course;
} public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public Date getBegin() {
return begin;
} public void setBegin(Date begin) {
this.begin = begin;
} public Date getEnd() {
return end;
} public void setEnd(Date end) {
this.end = end;
} public Teacher getTeacher() {
return teacher;
} public void setTeacher(Teacher teacher) {
this.teacher = teacher;
} public Course getCourse() {
return course;
} public void setCourse(Course course) {
this.course = course;
} @Override
public String toString() {
return "TeacherCourse [id=" + id + ", begin=" + begin + ", end=" + end + ", teacher=" + teacher + ", course="
+ course + "]";
} }

2)在mybatis-config.xml的<Mappers>下加一条:<mapper resource="com/cnblogs/oneToMany/OneToMany.xml" />  

3)sql映射文件

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="com.cnblogs.manyTOMany.ManyToMany">
<!-- 结果集映射关系 -->
<resultMap type="Teacher" id="TeacherBaseMap">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
<result property="title" column="t_title"/>
</resultMap> <resultMap type="Course" id="CourseBaseMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<result property="description" column="c_des"/>
</resultMap> <resultMap type="TeacherCourse" id="TeacherCourseBaseMap">
<id property="id" column="id"/>
<result property="begin" column="begin"/>
<result property="end" column="end"/>
</resultMap> <!-- 插入 -->
<insert id="insertTeacher" parameterType="Teacher"
useGeneratedKeys="true" keyProperty="id">
insert into teacher(t_name,t_title)
values(#{name},#{title})
</insert> <insert id="insertCourse" parameterType="Course"
useGeneratedKeys="true" keyProperty="id">
insert into course(c_name,c_des)
values(#{name},#{description})
</insert> <insert id="insertTeacherCourse" parameterType="TeacherCourse"
useGeneratedKeys="true" keyProperty="id">
insert into teacher_course(begin,end,t_id,c_id)
values(#{begin},#{end},#{teacher.id},#{course.id})
</insert> <!-- 嵌套结果映射
其实就是一对多查询,因为桥表的存在
-->
<resultMap type="Teacher" id="TeacherMap1"
extends="com.cnblogs.manyTOMany.ManyToMany.TeacherBaseMap">
<collection property="courses" resultMap="CourseBaseMap" column="c_id" />
</resultMap>
<!-- sql语句 -->
<select id="selectTeacherWithCourseById" parameterType="long" resultMap="TeacherMap1">
select * from teacher t,course c,teacher_course tc
where t.t_id=#{id} and t.t_id=tc.t_id and tc.c_id=c.c_id
</select> <!-- 嵌套结果查询 -->
<select id="selectCourseById" parameterType="long" resultMap="CourseBaseMap">
select * from course
where c_id=#{id}
</select>
<resultMap type="Teacher" id="TeacherMap2"
extends="com.cnblogs.manyTOMany.ManyToMany.TeacherBaseMap">
<collection property="courses" select="selectCourseById" column="c_id" />
</resultMap>
<select id="selectTeacherWithCourseById2" parameterType="long"
resultMap="TeacherMap2">
select * from teacher t,teacher_course tc
where t.t_id=#{id} and t.t_id=tc.t_id
</select>
</mapper>

 接口:

package com.cnblogs.manyTOMany;

import com.cnblogs.bean.Course;
import com.cnblogs.bean.Teacher;
import com.cnblogs.bean.TeacherCourse; public interface ManyToMany {
/**
* 插入一条教师数据
* @param teacher
*/
public abstract void insertTeacher(Teacher teacher); /**
* 插入一条课程数据
* @param course
*/
public abstract void insertCourse(Course course); /**
* 插入一条桥表数据
* @param tc
*/
public abstract void insertTeacherCourse(TeacherCourse tc); /**
* 嵌套结果映射
* 教师的详细信息
* @param id
* @return
*/
public abstract Teacher selectTeacherWithCourseById(Long id); /**
* 嵌套结果查询
* @param id
* @return
*/
public abstract Teacher selectTeacherWithCourseById2(Long id);
}

4)测试类

package com.cnblogs.jtest;

import java.io.IOException;
import java.util.Date; import org.apache.ibatis.session.SqlSession;
import org.junit.Test; import com.cnblogs.bean.Course;
import com.cnblogs.bean.Teacher;
import com.cnblogs.bean.TeacherCourse;
import com.cnblogs.manyTOMany.ManyToMany;
import com.cnblogs.utils.MySqlSessionFactory; public class ManyToManyTest {
@Test
public void insertTeacher() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
ManyToMany mapper = session.getMapper(ManyToMany.class);
// 准备数据
Teacher teacher1 = new Teacher("li","讲师");
Teacher teacher2 = new Teacher("zj","高级讲师");
Teacher teacher3 = new Teacher("kb","教授"); mapper.insertTeacher(teacher1);
mapper.insertTeacher(teacher2);
mapper.insertTeacher(teacher3); // 提交事务
session.commit();
} catch (IOException e) {
e.printStackTrace();
}
} @Test
public void insertCourse() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
ManyToMany mapper = session.getMapper(ManyToMany.class);
// 准备数据
Course course1 = new Course("core java","核心java基础");
Course course2 = new Course("c语言","ccc");
Course course3 = new Course("c++","c++++"); mapper.insertCourse(course1);
mapper.insertCourse(course2);
mapper.insertCourse(course3); // 提交事务
session.commit();
} catch (IOException e) {
e.printStackTrace();
}
} @Test
public void insertTeacherCourse() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
ManyToMany mapper = session.getMapper(ManyToMany.class);
// 准备数据
Course course1 = new Course();
course1.setId(1L);
Course course2 = new Course();
course2.setId(2L);
Course course3 = new Course();
course3.setId(3L); Teacher teacher1 = new Teacher();
teacher1.setId(4L);
Teacher teacher2 = new Teacher();
teacher2.setId(5L);
Teacher teacher3 = new Teacher();
teacher3.setId(6L); TeacherCourse tc1 = new TeacherCourse(new Date(),new Date(),teacher1,course1);
TeacherCourse tc2 = new TeacherCourse(new Date(),new Date(),teacher2,course2);
TeacherCourse tc3 = new TeacherCourse(new Date(),new Date(),teacher3,course3); mapper.insertTeacherCourse(tc1);
mapper.insertTeacherCourse(tc2);
mapper.insertTeacherCourse(tc3); // 提交事务
session.commit();
} catch (IOException e) {
e.printStackTrace();
}
} @Test
public void selectTeacherWithCourseById() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
ManyToMany mapper = session.getMapper(ManyToMany.class);
// 准备数据
Teacher t1 = mapper.selectTeacherWithCourseById(4L);
Teacher t2 = mapper.selectTeacherWithCourseById(6L); System.out.println("Teacher: " + t1);
System.out.println("Teacher: " + t2);
} catch (IOException e) {
e.printStackTrace();
}
} @Test
public void selectTeacherWithCourseById2() {
SqlSession session = null;
try {
session = MySqlSessionFactory.opensession();
ManyToMany mapper = session.getMapper(ManyToMany.class);
// 准备数据
Teacher t1 = mapper.selectTeacherWithCourseById2(4L);
Teacher t2 = mapper.selectTeacherWithCourseById2(6L); System.out.println("Teacher: " + t1);
System.out.println("Teacher: " + t2);
} catch (IOException e) {
e.printStackTrace();
}
}
}

总结:

  使用mybatis操作数据库,把配置文件配置好以后,就非常简单了,就像在sql命令行直接输入sql语句一样。

 要分清嵌套结果映射和嵌套结果查询的区别。

  * resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。

  * 一对一:重点掌握<association>标签在嵌套结果映射和嵌套结果查询中的使用

  * 一对多:重点掌握<collection>标签在嵌套结果映射和嵌套结果查询中的使用

  * 多对多:其实和一对多一样使用,不过多了一个桥接表。

mybatis还有更强大的功能:动态sql,将会在下篇使用。同时还会介绍mybatis  generator软件【一款根据数据库的表自动生成pojo类和sql映射文件】

  如何想了解更多mybatis,可以去看文档。中文文档网址:http://www.mybatis.org/mybatis-3。

java web(六):mybatis之一对一、一对多、多对多映射的更多相关文章

  1. mybatis入门_一对多,多对多映射以及整合spring框架

    一.一对多映射. 1.1 一对多映射之根据多的一方关联查询一的一方 示例:查询出具体的订单信息,同时也查询出来订单的用户信息. 引入的订单表如下所示: 框选出来的为具体的外键. 订单的Pojo类如下所 ...

  2. mybatis 一对一 一对多 多对多

    一对一 一对多 多对多

  3. JPA级联(一对一 一对多 多对多)注解【实际项目中摘取的】并非自己实际应用

    下面把项目中的用户类中有个:一对一  一对多  多对多的注解对应关系列取出来用于学习      说明:项目运行正常 问题类:一对多.一对一.多对多 ============一对多 一方的设置 @One ...

  4. Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作

    Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作,单表查询,多表查询 一丶表与表之间的关系 背景: ​ ​ ​  ​ ​ 由于如果只使用一张表存储所有的数据,就会操作数 ...

  5. java web(六)多个请求对应一个Servlet

    概要: 提交请求的常用方式有两种,get/post , 运行程序后被请求,在加载执行web.xml文件时通过该文件中的映射关系找到即将要执行的Servlet; 而在要执行的Servlet文件中可通过反 ...

  6. Java Web(六) JSP

    现在的Java Web开发已经很少使用JSP脚本了,业务逻辑都交给Servlet处理,JSP只负责显示视图,所以接下来的内容就对JSP脚本不做叙述了... JSP概述 JSP全名为Java Serve ...

  7. JPA 一对一 一对多 多对一 多对多配置

    1 JPA概述 1.1 JPA是什么 JPA (Java Persistence API) Java持久化API.是一套Sun公司 Java官方制定的ORM 方案,是规范,是标准 ,sun公司自己并没 ...

  8. day 69-70 一对一 一对多 多对一联表查询

    day 69 orm操作之表关系,多对多,多对一 多对一/一对多, 多对多{类中的定义方法} day69 1. 昨日内容回顾 1. 单表增删改查 2. 单表查询API 返回QuerySet对象的: 1 ...

  9. 使用NHibernate(7)-- 一对一 && 一对多 && 多对多

    1, 一对一. 对于数据量比较大的时候,考虑查询的性能,肯能会把一个对象的属性分到两个表中存放:比如用户和用户资料,经常使用的一般是Id和用户名,用户资料(学校,籍贯等)是不经常被查询的,所以就会分成 ...

随机推荐

  1. sed 命令简介

    sed 默认把文件内容全部显示出来(擅长取行  替换) 参数如下: - n 取消默认输出 一般与P一起使用 查看内容‘10,20p’   显示10-20 行的内容 - i 修改文件内容 - i.bak ...

  2. spring cloud 随笔记录(1)-

    最近随着微服务的火热,我也开始对我服务进行了解了  毕竟程序员这一行需要及时更新自己的技能,才能更好的生存. 我理解的微服务  项目由多个独立运行的程序组成,每个服务运行在自己的进程中,服务间采用轻量 ...

  3. JavaWeb基础-Jsp内置对象

    request对象 客户端的请求信息被封装在request对象中,通过它才能了解到客户的需求,然后做出响应,它是HttpServlteRequest类的实例.Request对象具有请求域,即完成客户端 ...

  4. Struts框架原理及应用

    Struts 2框架本身大致可以分为3个部分:核心控制器FilterDispatcher.业务控制器Action和用户实现的企业业务逻辑组件. 核心控制器FilterDispatcher是Struts ...

  5. L360 Most People Spend Their Time in Just 25 Places

    Some people are always out on the town, going to concerts, restaurant openings, you name it. They're ...

  6. Vim+Taglist+AutoComplPop之代码目录分栏信息和自动补全提示(Ubuntu环境)

    一步: 首先在Ubuntu环境中安装ctags:  sudo apt-get install ctags 第二部:       安装Taglist-------------Taglist是vim的一个 ...

  7. 十分钟搞定 pandas

    原文:http://pandas.pydata.org/pandas-docs/stable/10min.html 译者:ChaoSimple 校对:飞龙 官方网站上<10 Minutes to ...

  8. 百度翻译新API C#版在 winform,Asp.Net的小程序

    3月的下午,在C#群里日常装逼(聊天), 一兄弟说百度翻译有没有winfrom上用的Demo,问了一天  嫌烦了  我就干脆自己写个: PS 百度上的部分代码害死人啊  api地址都换的不成样了, 还 ...

  9. LSC问题(不连续问题)

    转载:http://blog.csdn.net/v_JULY_v/article/details/6110269 本文是动态规划算法中,网上写得最好的一个之一.看完很容易理解.需要重点理解的部分,我会 ...

  10. python 读取默认配置文件和用户配置文件 configs

    优先从configs_default中读取配置,但是configs_override中的配置可以override它 import configs_default #import configs_ove ...