1.表与表之间的关系及其举例
表之间的关系有4种:一对多、多对一、一对一、多对多。
举例: (1)用户和订单就是一对多一个用户可以下多个订单
(2)订单和用户就是多对一 多个订单属于同一个用户(3)人和身份证号就是一对一
一个人只能有一个身份证号 一个身份证号只能属于一个人(4)老师和学生之间就是多对多
一个学生可以被多个老师教过 一个老师可以交多个学生2.mybatis中的多表查询
示例:用户和账户 一个用户可以有多个账户 一个账户只能属于一个用户(多个账户也可以属于同一个用户) 步骤: 1、建立两张表:用户表,账户表 让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加 2、建立两个实体类:用户实体类和账户实体类 让用户和账户的实体类能体现出来一对多的关系 3、建立两个配置文件 用户的配置文件 账户的配置文件 4、实现配置: 当我们查询用户时,可以同时得到用户下所包含的账户信息 当我们查询账户时,可以同时得到账户的所属用户信息3.操作案例
(1)案例1
查询所有查询所有账户,及其用户名和地址信息(逻辑为:账户表account-----》用户信息表user)
<1>对数据库表Account对应的实体类Account.java进行改造,加入User对象作为成员变量
package domain;import java.io.Serializable;/** * 数据库的account表对应的实体类 */public class Account implements Serializable { private Integer id; private Integer uid; private Double money; //从表实体应该包含一个主表实体的对象引用 private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", uid=" + uid + ", money=" + money + '}'; }}
<2>IAccountDao中添加findAll()方法
package dao;import domain.Account;import domain.AccountUser;import java.util.List;public interface IAccountDao { /** * 查询所有查询所有账户,及其用户名和地址信息 * @return */ ListfindAll(); }
<3>映射关系配置
(1)IAccountDao.xml配置
ResultMap标签基本作用:建立SQL查询结果字段与实体属性的映射关系信息
标签属性id和type的含义:
id:该resultMap的标志
type:返回值的类名子标签含义:
id:用于设置主键字段与领域模型属性的映射关系,此处主键为ID,对应id。
result:用于设置普通字段与领域模型属性的映射关系 association 为关联关系,是实现一对一的关键 1. property 为javabean中容器对应字段名 2. javaType 指定关联的类型,当使用select属性时,无需指定关联的类型 3. select 使用另一个select查询封装的结果 4. column 为数据库中的列名,与select配合使用
注解配置:IAccountDao.java文件中进行如下配置
/** * 查询所有查询所有账户,及其用户名和地址信息 * 注解中的第四个result的column为uid(外键),连接到user表,select调用dao.IUserDao.findById()方法 * @return */ @Select("select * from account") @Results(id="accountMap",value = { @Result(id=true,column = "id",property = "id"), @Result(column = "uid",property = "uid"), @Result(column = "money",property = "money"), @Result(column = "uid",property = "user",one=@One(select = "dao.IUserDao.findById",fetchType = FetchType.EAGER)) }) ListfindAll();
<4>测试代码
package test;import dao.IAccountDao;import dao.IUserDao;import domain.Account;import domain.AccountUser;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 java.io.InputStream;import java.util.List;public class MybatisTest01 { private InputStream in; private SqlSession sqlSession; private IAccountDao accountDao; /** * 初始化MyBatis * @throws Exception */ public void initMyBatis() throws Exception{ //1.读取配置文件 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建SqlSessionFactory SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //创建SqlSessionFactory的构建者builder SqlSessionFactory factory=builder.build(in); //利用构建者builder创建SqlSessionFactory //3.使用工厂生产SqlSession对象 sqlSession = factory.openSession(); //4.使用SqlSessions对象创建Dao接口的代理对象 accountDao = sqlSession.getMapper(IAccountDao.class); } /** * 释放资源 * @throws Exception */ public void destroy() throws Exception{ sqlSession.commit();//提交事务 sqlSession.close(); in.close(); } /** * 查询所有 * @throws Exception */ @Test public void testFindAll()throws Exception{ initMyBatis(); Listaccounts = accountDao.findAll(); for (Account account : accounts) { System.out.println(account); System.out.println(account.getUser()); } destroy(); } }
效果图:
(2)案例2
查询所有查询用户信息,及其拥有的账户信息(逻辑为:用户信息表user-----》账户表account)
<1>对数据库表user对应的实体类User.java进行改造,加入List<Account>作为成员变量
package domain;import java.io.Serializable;import java.util.Date;import java.util.List;/** * 数据库表对应的实体类 */public class User implements Serializable { //实体类的成员变量名称应该与数据库中的列名一致 private Integer id; private String username; private Date birthday; private String sex; private String address; private Listaccounts; public List getAccounts() { return accounts; } public void setAccounts(List accounts) { this.accounts = accounts; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}'; }}
<2>IUserDao中添加findAll()方法
package dao;import domain.User;import java.util.List;/** * */public interface IUserDao { /** * 查询所有 * @return */ ListfindAll();}
<3>IUserDao.xml
ResultMap标签基本作用:建立SQL查询结果字段与实体属性的映射关系信息
标签属性id和type的含义:
id:该resultMap的标志
type:返回值的类名子标签含义:
id:用于设置主键字段与领域模型属性的映射关系,此处主键为ID,对应id。
result:用于设置普通字段与领域模型属性的映射关系 association 为关联关系,是实现一对一的关键 1. property 为javabean中容器对应字段名 2. javaType 指定关联的类型,当使用select属性时,无需指定关联的类型 3. select 使用另一个select查询封装的结果 4. column 为数据库中的列名collection 为关联关系,是实现一对多的关键
1. property 为javabean中容器对应字段名 2. ofType 指定集合中元素的对象类型 3. select 使用另一个查询封装的结果 4. column 为数据库中的列名,与select配合使用注解配置:IUserDao.java文件中进行如下配置
/** * 查询所有 * @return */ @Select("select * from user") @Results(id="userMap",value = { @Result(id=true,column = "id",property = "id"), @Result(column = "username",property = "username"), @Result(column = "address",property = "address"), @Result(column = "sex",property = "sex"), @Result(column = "birthday",property = "birthday"), @Result(column = "id",property ="accounts",many =@Many(select = "dao.IAccountDao.findAccountById",fetchType = FetchType.EAGER)) }) ListfindAll();
<4>测试代码
package test;import dao.IAccountDao;import dao.IUserDao;import domain.Account;import domain.AccountUser;import domain.User;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 java.io.InputStream;import java.util.List;public class MybatisTest02_User { private InputStream in; private SqlSession sqlSession; private IUserDao userDao; /** * 初始化MyBatis * @throws Exception */ public void initMyBatis() throws Exception{ //1.读取配置文件 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建SqlSessionFactory SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //创建SqlSessionFactory的构建者builder SqlSessionFactory factory=builder.build(in); //利用构建者builder创建SqlSessionFactory //3.使用工厂生产SqlSession对象 sqlSession = factory.openSession(); //4.使用SqlSessions对象创建Dao接口的代理对象 userDao = sqlSession.getMapper(IUserDao.class); } /** * 释放资源 * @throws Exception */ public void destroy() throws Exception{ sqlSession.commit();//提交事务 sqlSession.close(); in.close(); } /** * 查询所有 * @throws Exception */ @Test public void testFindAll()throws Exception{ initMyBatis(); Listusers = userDao.findAll(); for (User user : users) { System.out.println(user); System.out.println(user.getAccounts()); } destroy(); }}
效果图:
4.Mybatis中的缓存
(1)什么是缓存 存在于内存中的临时数据。(2)为什么使用缓存 减少和数据库的交互次数,提高执行效率。(3)什么样的数据能使用缓存,什么样的数据不能使用 <1>适用于缓存: 经常查询并且不经常改变的。 数据的正确与否对最终结果影响不大的。 <2>不适用于缓存: 经常改变的数据 数据的正确与否对最终结果影响很大的。 例如:商品的库存,银行的汇率,股市的牌价。5.Mybatis中的一级缓存和二级缓存(1)一级缓存: 它指的是Mybatis中SqlSession对象的缓存。 当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。 该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中 查询是否有,有的话直接拿出来用。 当SqlSession对象消失时,mybatis的一级缓存也就消失了。(2)二级缓存: 它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。 二级缓存的使用步骤: 第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置) 第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置) 第三步:让当前的操作支持二级缓存(在select标签中配置)