菜鸟学习Mybatis一对一与一对多查询

一、关联查询

1.项目不可能只有一个表,一般是多表
2.多表关系为,一对一,一对多,多对多
3.查询的数据来自多个表,要使用多表查询
笛卡尔集,显示内连接inner join,左外连接left outer join,右外连接right outer join,子查询select嵌套select
4.查询的结果要封装成javaBean对象 ,在Mybatis中重点掌握resultType与resultMap
在这里插入图片描述

二、一对一关联实现

(1).关联查询的中的一对一是指,站在订单的角度看,一个订单有一个用户跟它对应
(2)数据来自两个表,使用连接查询,需要输出所有订单,使用左外连接
(3)查询结果可以有两种方式封装数据
》resultType 指定一个自定义javaBean类(通常要再编写一个新的javaBean类)
》resultMap 指定映射关系(不用编写新的javaBean类 推荐使用)
映射文件

1. 创建数据库表person和card

(一对一关联,一个表的外键是另一个表的主键,在哪个表创建外键都可以)


– 身份证card表,主键id自动增长


DROP TABLE IF EXISTS card;
CREATE TABLE card (
id int(11) NOT NULL AUTO_INCREMENT,
code varchar(18) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO card VALUES (‘1’, ‘111111111123456789’);
INSERT INTO card VALUES (‘2’, ‘222222222223456789’);
INSERT INTO card VALUES (‘3’, ‘333333333333456789’);


– 人 person表,主键id自动增长,在person表中设置card表的主键id作为外键


DROP TABLE IF EXISTS person;
CREATE TABLE person (
id int(11) NOT NULL AUTO_INCREMENT,
username varchar(20) DEFAULT NULL,
id_card int(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY FK_person_card (id_card),
CONSTRAINT FK_person_card FOREIGN KEY (id_card) REFERENCES card (id)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO person VALUES (‘1’, ‘张三’, ‘1’);
INSERT INTO person VALUES (‘2’, ‘李四’, ‘2’);
INSERT INTO person VALUES (‘3’, ‘王五’, ‘3’);

2. 创建bean对象

//person表
public class Person {
private Integer id;
private String username;
private Card card; // 1 111111111123456789
//省略getter/setter方法
}

//card表
public class Card {
private Integer id;
private String code;
//省略getter/setter
}

3. 创建dao层映射层

@Repository
public interface CardMapper {

//通过id来查询身份证表Card的信息
public Card getCardById(Integer id);

}

@Repository
public interface PersonMapper {

//通过一条Sql语句来查询
Person getPersonById(int id);

//通过嵌套查询
Person getPersonById2(int id);

//通过用户名查询
Person getPersonByName(String username);

}

4. 创建连接数据库的属性文件db.properties(键值对形式)

jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8
jdbc.username = root
jdbc.password = 861221293

5. spring整合MyBatis,核心配置文件

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<!--1. 引入jdbc的属性文件,在配置中通过占位使用 -->
<context:property-placeholder location="classpath*:db.properties" />

<!--2. <context:component-scan>扫描包中注解所标注的类(@Component、@Service、@Controller、@Repository) -->
<context:component-scan base-package="com.xgf.correlation.one_to_one"/>

<!--3. 由spring管理    配置数据源数据库连接(从jdbc属性文件中读取参数) -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
</bean>

<!--  通过spring来管理Mybatis的sqlSessionFactory对象创建  -->
<!--4. 通过完全限定名匹配查找  创建SqlSessionFactoryBean  -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 5. mybatis提供的一个注解扫描标签(搜索映射器 Mapper 接口),通过自动扫描注解的机制,创建每个dao接口定义的bean  -->
<mybatis:scan base-package="com.xgf.correlation.one_to_one"/>

<!-- 6. 配置事务管理器 完成手动事务管理  由spring管理事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<!--
    支持注解驱动的事务管理,指定事务管理器。
    配置事务 提供回滚,发生异常数据回滚  需要在类/方法上写注解 @Transactional -->
<tx:annotation-driven transaction-manager="transactionManager"/>

6. 创建映射文件mapper.xml

这里通过两种方式来查询

第一种(getPersonById)直接通过一条SQL语句查询
第二种(getPersonById2)嵌套sql查询,第二种才需要创建card表的映射文件【推荐使用第二种】
PersonMapper.xml

<!-- 1. 通过一条SQL语句查询主表+关联表双表信息 autoMapping="true"自动映射,如果表列名和对象属性名一致,可以不用配置<result>-->
<resultMap id="personMap" type="com.xgf.correlation.one_to_one.bean.Person" autoMapping="true">
    <!--<id>主键   <result>其它属性列  -->
   <id property="id" column="id"/>
   <result property="username" column="username"/>

    <!--  封装person对象对应的card
          一对一关联 用association封装对象类型
    -->
   <association property="card" javaType="com.xgf.correlation.one_to_one.bean.Card">
       <id property="id" column="id"/>
       <result property="code" column="code"/>
   </association>

</resultMap>
<select id="getPersonById" resultMap="personMap">
    select p.id,p.username,c.id,c.code
    from person p inner join card c on p.id_card = c.id
    where p.id = #{id}
</select>

<select id="getPersonByName" resultMap="personMap">
    select p.id,p.username,c.id,c.code
    from person p inner join card c on p.id_card = c.id
    where p.username = #{username}
</select>



<!--2. 嵌套查询实现 - 通过分布加载方式加载(嵌套select)
     通过多条SQL语句查询主表=关联表信息  一对一分布加载
-->

<!-- association select通过命名空间 + sql语句的id 来查询
      column对应主键id  foreignColumn外键
      column="id"  card表中的主键   foreignColumn="id_card"  person表的外键
 -->

<resultMap id="personMap2" type="com.xgf.correlation.one_to_one.bean.Person">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <association property="card" javaType="com.xgf.correlation.one_to_one.bean.Card"
                 select="com.xgf.correlation.one_to_one.dao.CardMapper.getCardById"
                 column="id"
                 foreignColumn="id_card"
    />
</resultMap>

<select id="getPersonById2" resultMap="personMap2" parameterType="int">
    select id,username
    from person
    where id=#{id}
</select>

CardMapper.xml

<select id="getCardById" parameterType="int" resultType="com.xgf.correlation.one_to_one.bean.Card">
    select id,code
    from card
    where id=#{id}
</select>

7. 创建测试类

测试结果
test01() 测试getPersonById结果(一条sql查两表)

Person{id=1, username=‘张三’, card=Card{id=1, code=‘111111111123456789’}}

test02()测试getPersonById2结果(嵌套查询)

Person{id=2, username=‘李四’, card=Card{id=2, code=‘222222222223456789’}}

test03()测试getPersonByName结果(用户名查找)

Person{id=2, username=‘王五’, card=Card{id=2, code=‘333333333333456789’}}

三、一对多关联实现

1. 创建users表(一)和task表(多)


– users表,主键id自动增长


DROP TABLE IF EXISTS users;
CREATE TABLE users (
id int(11) NOT NULL AUTO_INCREMENT,
username varchar(30) NOT NULL,
password varchar(30) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=100050 DEFAULT CHARSET=utf8;

INSERT INTO users VALUES (‘100001’, ‘用户100001’, ‘123456’);
INSERT INTO users VALUES (‘100002’, ‘用户100002’, ‘123679’);
INSERT INTO users VALUES (‘100003’, ‘用户100003’, ‘8888888’);
INSERT INTO users VALUES (‘100004’, ‘张三’, ‘8888888’);
INSERT INTO users VALUES (‘100005’, ‘李四’, ‘8888888’);
INSERT INTO users VALUES (‘100007’, ‘王五’, ‘8888888’);
INSERT INTO users VALUES (‘100008’, ‘赵六’, ‘8888888’);


– task表,主键自动增长,外键userId关联映射users表的主键id


DROP TABLE IF EXISTS task;
CREATE TABLE task (
id int(11) NOT NULL AUTO_INCREMENT,
taskName varchar(100) DEFAULT NULL,
userId int(11) DEFAULT NULL,
PRIMARY KEY (id),
KEY FK_users_task (userId),
CONSTRAINT FK_users_task FOREIGN KEY (userId) REFERENCES users (id)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;


– Records of task


INSERT INTO task VALUES (‘1’, ‘软件开发’, ‘100001’);
INSERT INTO task VALUES (‘2’, ‘软件测试’, ‘100002’);
INSERT INTO task VALUES (‘3’, ‘项目经理’, ‘100003’);
INSERT INTO task VALUES (‘4’, ‘集成开发’, ‘100001’);

2. 创建javabean对象

user和task是一对多的关联关系,在User类中要有一个Task集合来存储(taskList)

public class Task {
private Integer id;
private String taskName;
//省略getter/setter等方法
}

// 一个user有多个Task
public class User {

private Integer id;
private String username;
private String password;

// 一的一方保留多的一方信息
private List taskList;
//省略gettser/setter等方法
}

3. 创建dao层接口

@Repository
public interface TaskMapper {

//通过useId查询当前user的task列表
public List<Task> getTaskListByUid(Integer uid);

}

@Repository
public interface UserMapper {

//1.一条sql查询(通过内连接、外连接)
User getUserTaskById(int id);
//2.嵌套查询,分布查询加载【推荐】
User getUserTaskById2(int id);

}

4. 创建连接数据库的属性文件db.properties(键值对形式)

jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8
jdbc.username = root
jdbc.password = 861221293

5. spring整合MyBatis,核心配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<!--1. 引入jdbc的属性文件,在配置中通过占位使用 -->
<context:property-placeholder location="classpath*:db.properties" />

<!--2. <context:component-scan>扫描包中注解所标注的类(@Component、@Service、@Controller、@Repository) -->
<context:component-scan base-package="com.xgf.correlation.one_to_many"/>

<!--3. 由spring管理    配置数据源数据库连接(从jdbc属性文件中读取参数) -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
</bean>

<!--  通过spring来管理Mybatis的sqlSessionFactory对象创建  -->
<!--4. 通过完全限定名匹配查找  创建SqlSessionFactoryBean  -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 5. mybatis提供的一个注解扫描标签(搜索映射器 Mapper 接口),通过自动扫描注解的机制,创建每个dao接口定义的bean  -->
<mybatis:scan base-package="com.xgf.correlation.one_to_many"/>

6. 创建映射文件mapper.xml

单条sql语句,一次查询出
嵌套查询(这个才需要TaskMapper.xml映射)
UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!-- 通过一条sql(inner join内连接)语句关联查询,一对多关联关系 user和task表
    id:主键   result:其他键
    autoMapping="true" 开启自动映射,如果列名和属性名
    collection一对多关联映射
        property:对应javabean中创建的属性名(一个user对应多个task创建的集合taskList)
        ofType:是对应的完全限定名
-->
    <collection property="taskList" ofType="com.xgf.correlation.one_to_many.bean.Task" >
        <id column="tid" property="id"/>
        <result column="taskName" property="taskName"/>
    </collection>
</resultMap>

<select id="getUserTaskById" resultMap="userTaskMap1">
    SELECT u.id,u.username,u.password,t.id tid,t.taskName
    from users u inner join task t on u.id = t.userId
    where u.id=#{id}
</select>

<!-- 2. 嵌套查询【推荐使用】分步查询、分布加载-->
<!-- 配置 lazy懒加载,适用于单表查询提高效率,但是多表关联查询效率可能降低 通过fetchType配置懒加载
 需要在mybaits-config.xml核心配置文件中配置 settings
    懒加载 只有需要用到的时候才加载,不需要用到的时候就不加载,单表时可提高效率
 -->
<!-- collection  cloumn为一对多的 多表的主键 foreignColum以一表的外键-->
<resultMap id="userTaskMap2" type="com.xgf.correlation.one_to_many.bean.User" autoMapping="true">
     <id column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="password" property="password"/>
    <collection property="taskList"
                ofType="com.xgf.correlation.one_to_many.bean.Task"
                column="id"
                foreignColumn="userId"
                select="com.xgf.correlation.one_to_many.dao.TaskMapper.getTaskListByUid" fetchType="lazy"/>

</resultMap>

<select id="getUserTaskById2" parameterType="int" resultMap="userTaskMap2">
    select id,username,password
    from users
    where id = #{id}
</select>

TaskMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<select id="getTaskListByUid" parameterType="int"
        resultType="com.xgf.correlation.one_to_many.bean.Task">

    select id,taskName,userId from task where userId=#{userId}
</select>

7. 创建测试类

//测试类
public class TestOneToMany {

private static ApplicationContext applicationContext = null;
private static UserMapper userMapper = null;

//静态代码块 只加载一次
static {
    //加载配置文件
    applicationContext = new ClassPathXmlApplicationContext("com/xgf/correlation/one_to_many/config/applicationContext.xml");
    //获取bean的两种方式
    // 1.类名首字母小写

// studentMapper = (StudentMapper) applicationContext.getBean(“userMapper”);
// 2.类.class
userMapper = (UserMapper) applicationContext.getBean(UserMapper.class);
}

//第一种(getUserTaskById)直接通过id一条SQL语句查询
@Test
public void test01(){
    System.out.println("===一条SQL语句查询  查找id为100001的user和他的task列表:===");
    User user = userMapper.getUserTaskById(100001);
    System.out.println(user);
}

//第二种(getUserTaskById2)通过嵌套查询实现
@Test
public void test02(){
    System.out.println("===嵌套查询  查找id为100002的user和他的task列表===");
    User user = userMapper.getUserTaskById2(100002);
    System.out.println(user);
}

}

测试结果
test01测试getUserTaskById(一条sql查询)

User{id=100001, username=‘用户100001’, password=‘123456’, taskList=[Task{编号=1, 任务名=‘软件开发’}, Task{编号=4, 任务名=‘集成开发’}]}

test02测试getUserTaskById2(嵌套查询)

User{id=100002, username=‘用户100002’, password=‘123679’, taskList=[Task{编号=2, 任务名=‘软件测试’}]}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值