1.ORM框架mybatis的基本介绍(包括配置文件):
ORM可以解决数据库与程序间的异构性,比如在Java中我们使用String表示字符串,而Oracle中可使用varchar2,MySQL中可使用varchar,SQLServer可使用nvarchar。
ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象与关系数据库相互映射。
没有ORM时我们是这样完成对象与关系数据库之间的映射的:
//将执行的sql
String sql = "SELECT name, id, age, password FROM users";
//创建命令对象
preparedStatement = connection.prepareStatement(sql);
//执行并获得结果集
resultSet = preparedStatement.executeQuery();
//遍历结果集,将数据库中的数据转换成Java中的对象
while(resultSet.next()){
String name = resultSet.getString("name");
int id = resultSet.getInt("id");
int age = resultSet.getInt("age");
String password = resultSet.getString("password");
User entity= new User(name,id,age,password);
Users.add(entity);
}
这种写法的不足:
- 原生的jdbc会频繁的创建链接和释放资源,会增加数据库的链接压力
解决方法:使用连接池,用连接池来管理数据库的链接和释放资源。 - 原生的jdbc的sql语句是写在java代码中的,这种方式属于硬编码,不利于sql代码的维护。
解决方法:mybatis框架将sql语句提取到xml配置文件中,每一次修改sql语句,只需要修改配置文件中的语句即可,和代码无关 - 原生的jdbc预编译对象中的?也属于硬编码
解决方法:mybatis框架将视线关系对象映射,mybatis存在输入对象映射和输出对象映射。
原生的jdbc:
public class Demo{
private static String driver = "com.mysql.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/db_shop";
private static String username = "root";
private static String password = "";
static{
//加载驱动
Class.forName(driver);
}
public static void main(String[] args){
try{
Connection conn = ManagerDriver.getConnection(url,username,password);
String sql = "select * from student where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,user.getInt());
ResultSet rs = ps.executeQuery();
while(rs.next()){
}
rs.close();
ps.close();
conn.close();
}catch(Exception e){
}
}
}
mybatis概念:
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
案例代码:查询
这是mybatis基本的框架
编写sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 使用mybatis需要的数据源和事务配置,后续如果整合spring之后,将不再需要 -->
<environments default="development">
<!-- 配置数据源和事务 -->
<environment id="development">
<!-- 配置事务管理,将事务管理交给mybatis管理 -->
<transactionManager type="JDBC" />
<!-- 配置数据源 -->
<dataSource type="POOLED">
<property name = "driver" value = "com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!-- 加载**.xml配置文件 -->
<mappers>
<mapper resource="Food.xml"/>
</mappers>
</configuration>
编写log4j.properties标签
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
编写失血模型对象:food模型
package model;
/**
* @ClassName: food.java
* @Description: 该类的功能描述
* @version: v1.0.0
* @author: 169986432
* @date: 2020年10月11日 下午2:38:05
*/
public class Food {
private int id;
private String last_name;
private String gender;
private String email;
public Food() {
super();
}
public Food(int id, String last_name, String gender, String email) {
super();
this.id = id;
this.last_name = last_name;
this.gender = gender;
this.email = email;
}
/**
* @return the id
*/
public int getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return the last_name
*/
public String getLast_name() {
return last_name;
}
/**
* @param last_name the last_name to set
*/
public void setLast_name(String last_name) {
this.last_name = last_name;
}
/**
* @return the gender
*/
public String getGender() {
return gender;
}
/**
* @param gender the gender to set
*/
public void setGender(String gender) {
this.gender = gender;
}
/**
* @return the email
*/
public String getEmail() {
return email;
}
/**
* @param email the email to set
*/
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Food [id=" + id + ", last_name=" + last_name + ", gender=" + gender + ", email=" + email + "]";
}
}
编写单个映射关系的sql.xml:Food.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="test">
<select id="foodAll
" parameterType="java.lang.Integer" resultType="model.Food">
SELECT * FROM food WHERE last_anme= #{value}
</select>
</mapper>
编写dao接口:查询的接口
public interface FoodDao {
public Food queryProductById(String last_name) throws Exception;
}
编写dao接口的实现类:FoodImpl实现类
public class FoodDaoImpl implements FoodDao {
//声明一个会话工厂
private SqlSessionFactory factory;
//由构造方法进行创建对象赋值
public FoodDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
@Override
public Food queryProductById(String last_name) throws Exception {
//开启会话
SqlSession sqlSession = factory.openSession();
Food prod = sqlSession.selectOne("test.foodAll", last_name);
//关闭会话
sqlSession.close();
return prod;
}
}
测试类:测试
public class Test {
//创建dao的实现类
public static void main(String[] args) throws Exception{
String path = "SqlMapConfig.xml";
InputStream config = Resources.getResourceAsStream(path);
//创建一个会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);
testQuery1(factory);
}
public static void testQuery1(SqlSessionFactory factory) throws Exception {
FoodDao dao = new FoodDaoImpl(factory);
int id = 1;
Food food=dao.queryProductById("张三");
System.out.println(food);
}
}
mybatis的最简单的增,删,改,查
思路:
1.导入jr包,创建xml里面配置增,删,改。查的sql语句
2.创建xml文件在SqlMapConfig.xml文件中进行配置加载
3.创建一个失血模型要跟数据库的字段一致
4.创建一个接口,接口当中包含5个方法,两个查询、增、删、改的方法。只有定义。
5.创建实现类,实现定义的接口,按照规定进行重写方法。声明工厂类对象,该对象由该类的构造方法进行赋值。
6.编写测试类,在测试类中,创建工厂对象,传递给dao的实现类。
代码:
编写xml:food.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="first">
<!-- 根据id查询 -->
<select id="queryId" parameterType="java.lang.Integer" resultType="model.Food">
SELECT * FROM t_product WHERE p_id = #{p_id}
</select>
<!-- 根据名称模糊查询,返回多条结果集 -->
<select id="queryName" parameterType="java.lang.String" resultType="model.Food">
SELECT * FROM t_product WHERE name like "%${value}%"
</select>
<!-- 新增一条数据 -->
<insert id="insert" parameterType="model.Food">
INSERT INTO t_product(name,p_number,price) value(#{name},#{p_number},#{price})
</insert>
<!-- 根据id值更新 -->
<update id="update" parameterType="model.Food">
UPDATE t_product SET name = #{name} WHERE p_id = #{p_id}
</update>
<!-- 根据id删除 -->
<delete id="delete" parameterType="java.lang.Integer">
DELETE FROM t_product WHERE p_id = #{p_id}
</delete>
</mapper>
编写xml:加载food。xml
编写接口增,删,改,查
public interface FoodDao {
public Food queryId(int id) throws Exception;
public List<Food> queryName(String name) throws Exception;
public Food insert(Food product) throws Exception;
public int update(Food product) throws Exception;
public int delete(int id) throws Exception;
}
编写接口的实现类
public class FoodDaoImpl implements FoodDao {
//声明一个会话工厂
private SqlSessionFactory factory;
//由构造方法进行创建对象赋值
public FoodDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
@Override
public Food queryId(int id) throws Exception {
SqlSession sqlSession = factory.openSession();
Food food= sqlSession.selectOne("first.queryId", id);
sqlSession.close();
return food;
}
@Override
public List<Food> queryName(String name) throws Exception {
SqlSession sqlSession = factory.openSession();
List<Food> list = sqlSession.selectList("first.queryName", name);
sqlSession.close();
return list;
}
@Override
public Food insert(Food food) throws Exception {
SqlSession sqlSession = factory.openSession();
int row = sqlSession.insert("first.insert", food);
sqlSession.commit();
sqlSession.close();
return food;
}
@Override
public int update(Food food) throws Exception {
SqlSession sqlSession = factory.openSession();
int row = sqlSession.update("first.update", food);
sqlSession.commit();
sqlSession.close();
return row;
}
@Override
public int delete(int id) throws Exception {
SqlSession sqlSession = factory.openSession();
int row = sqlSession.delete("first.delete", id);
sqlSession.commit();
sqlSession.close();
return row;
}
}
测试类:测试
public class Test {
//创建dao的实现类
public static void main(String[] args) throws Exception{
String path = "SqlMapConfig.xml";
InputStream config = Resources.getResourceAsStream(path);
//创建一个会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);
// testQuery1(factory);
// testQuery2(factory);
testQuery3(factory);
}
public static void testQuery1(SqlSessionFactory factory) throws Exception {
FoodDao dao = new FoodDaoImpl(factory);
int id = 1;
Food food = dao.queryId(id);
System.out.println(food);
}
public static void testQuery2(SqlSessionFactory factory) throws Exception {
FoodDao dao = new FoodDaoImpl(factory);
String name = "牛奶";
List<Food> list = dao.queryName(name);
System.out.println(list);
}
public static void testQuery3(SqlSessionFactory factory) throws Exception {
SqlSession session = factory.openSession();
Food food=session.getMapper(Food.class);
Food food1=new Food();
food1.setP_id(7);
food1.setName("阿萨姆奶茶");
food1.setP_number(788);
food1.setPrice(90);
food1.setAdd_time("2020-09-23 17:59:46.0");
}
}
mapper代理的方式进行讲解增、删、改、查(重点)
配置xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 修改数据库的四个连接属性 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!-- 配置sql语句 的那个mapper配置文件 -->
<mappers>
<mapper resource="com/dao/UserMapper.xml"/>
</mappers>
</configuration>
Mapper代码:
public interface UserMapper {
// 保存
public int save(Food Food);
// 更新
public intupdate(Food Food);
// 根据id删除
public int deleteId(int id);
// 根据id搜索
public User findId(int id);
// 搜索全部
public List<User> findFood();
}
配置FoodMapper.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.dao.UserMapper">
<!-- public Integer save(Food FoodUser user); -->
<insert id="saveUser" parameterType="com.pojo.Food">
insert into t_user(`last_name`,`sex`) values(#{lastName},#{sex})
</insert>
<!-- public Integer updateUser(Food Food); -->
<update id="updateUser" parameterType="com.pojo.Food">
update t_user set last_name = #{lastName} , sex = #{sex} where id = #{id}
</update>
<!-- public Integer deleteUserById(Integer id); -->
<delete id="deleteUserById">
delete from t_user where id = #{id}
</delete>
<!-- public User findUserById(Integer id); -->
<select id="findUserById" resultType="com.pojo.Food">
select id,last_name lastName,sex from t_user where id = #{id}
</select>
<!-- public List<User> findUsers(); -->
<select id="findUsers" resultType="com.pojo.Food">
select id,last_name lastName,sex from t_user
</select>
</mapper>
测试类:
public class FoodMapperTest {
static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
String url = "mybatis-config.xml";
// 读取配置文件
InputStream inputStream = Resources.getResourceAsStream(url);
// 创建SqlSessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testSave() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User(0, "ddddd", 1);
userMapper.saveUser(user);
session.commit();
System.out.println(user);
} finally {
session.close();
}
}
@Test
public void testUpdateUser() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User(4, "eeeee", 1);
userMapper.updateUser(user);
session.commit();
} finally {
session.close();
}
}
@Test
public void testDeleteById() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
userMapper.deleteUserById(4);
session.commit();
} finally {
session.close();
}
}
@Test
public void testFindById() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
System.out.println(userMapper.findUserById(1));
} finally {
session.close();
}
}
@Test
public void testFind() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
System.out.println(userMapper.findUsers());
} finally {
session.close();
}
}
效果:
别名和mapper映射详解
设置别名:
1.设置别名位置是在SqlMapConfig.xml配置文件中
<!-- 设置一个别名 -->
<typeAliases>
<!--
type: 要设置的model全路径名
alias:取的别名
-->
<typeAlias type="com.woniuxy.mall.model.User" alias="user"/>
</typeAliases>
2.推荐使用批量设置别名,扫描model包
<typeAliases>
<!--
name:包名
-->
<package name="com.woniuxy.mall.model"/>
</typeAliases>
Mapper映射关系配置
以mapper.xml配置文件的方式
以配置Mapper接口的方式进行配置
<!-- 加载mapper.xml文件 -->
<mappers>
<!--
class:对应接口的全路径名
要求:
对应的mapper.java接口文件和mapper.xml配置文件必须放在同一个包下面。
mapper.java接口文件和mapper.xml配置文件的名字必须要一致。
-->
<mapper class="mapper.FoodMapper"/>
</mappers>
以扫描包的形式进行配置
<!-- 加载mapper.xml文件 -->
<mappers>
<!--
name:mapper接口的包名
规则同上。
-->
<package name="mapper"/>
</mappers>
自定义的POJO类
自定义POJO类,一般指的是高级查询,在想要的数据和传入的条件不再一张表中,通过表所创建的失血模型model已经不能够满足传入参数的需求了,这个时候,就需要使用自定义的POJO类
因为一个失血模型已经不能够满足查询输入参数的要求了,所以进行扩展,创建一个UserCustom类,里面包含user对象声明和userInfo对象声明
Customer 实体类:
public class Customer {
private List<Orders> orders; // 关联多个订单
private Integer id;
private String name;
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 List<Orders> getOrders() {
return orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
}
Orders 实体类:
public class Orders {
private Integer id;
private String sn; // 订单编号
private String remark; // 订单描述
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
创建 CustomerMapper.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="yeepay.payplus.mapper.CustomerMapper">
<resultMap type="yeepay.payplus.domain.Customer" id="customerRM">
<id property="id" column="ID"/>
<result property="name" column="NAME"/>
</resultMap>
<!-- 配置关联关系 1:N -->
<resultMap type="yeepay.payplus.domain.Customer" id="customerOrdersRM" extends="customerRM">
<!-- 配置多的(N),property 属性就是实体中的 List 对象属性名称,ofType 属性就是集合元素的类型 -->
<collection property="orders" ofType="yeepay.payplus.domain.Orders">
<id property="id" column="ID"/>
<result property="sn" column="SN"/>
<result property="remark" column="REMARK"/>
</collection>
</resultMap>
<!-- 查询,关联关系 Map 作为查询条件 -->
<select id="find" parameterType="map" resultMap="customerOrdersRM">
SELECT
c.name,o.sn,o.remark
FROM
(SELECT id,name FROM customer) c
LEFT JOIN
(SELECT id,sn,remark,customer_id FROM orders) o
ON c.id = o.customer_id
WHERE c.name = #{customerName}
</select>
</mapper>
sqlMapConfig.xml 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 赋别名 -->
<typeAliases>
<typeAlias type="yeepay.payplus.domain.Person" alias="Person"/>
</typeAliases>
<!-- 配置开发环境,可以配置多个,在具体用时再做切换 -->
<environments default="">
<environment id="test">
<transactionManager type="JDBC"></transactionManager> <!-- 事务管理类型:JDBC、MANAGED -->
<dataSource type="POOLED"> <!-- 数据源类型:POOLED、UNPOOLED、JNDI -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 mapper -->
<mappers>
<!-- 路径用 斜线(/) 分割,而不是用 点(.) -->
<mapper resource="yeepay/payplus/mapper/UserMapper.xml"/>
<mapper resource="yeepay/payplus/mapper/CustomerMapper.xml"/>
</mappers>
</configuration>
创建 CeshiCustomer 测试类
public class CeshiCustomer {
@Test
public void testFind() throws IOException {
/**
* 1、获得 SqlSessionFactory
* 2、获得 SqlSession
* 3、调用在 mapper 文件中配置的 SQL 语句
*/
String resource = "sqlMapConfig.xml"; // 定位核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 创建 SqlSessionFactory
SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取到 SqlSession
Map map = new HashMap();
map.put("customerName", "charies");
// 调用 mapper 中的方法:命名空间 + id
List<Customer> customerList = sqlSession.selectList("yeepay.payplus.mapper.CustomerMapper.find", map);
for (Customer c : customerList) {
System.out.println(c);
}
}
输入映射:目前在mybatis用到的都是parameterType类型,其中可以是简单数据类型,也可以是包装类型(POJO)
parameterType:java.lang.Integer\java.lang.String\POJO模型类。
输出映射
- 输出的类型为POJO包装类(model失血模型),用的是resultType
- 输出的类型为简单数据类型,resultType,要求:查询的结果集必须是一行一列的数据
- 输出类型为resultMap方式,当前的作用,当java中失血模型对象中的字段和数据库中的字段名称不一致的时候,可以使用resultMap方式进行自定义映射关系。
代码:
<resultMap type="User" id="userResult">
<!-- id: 用来关联在查询结果集中可以唯一识别一个实体的字段,一般都是主键
column:在查询结果集中,能够唯一识别一个实体的字段名
property:结果集中的数据和失血模型中对应的属性名。
-->
<id column="id" property="user_id"/>
<!--
result:除了能唯一识别实体字段以外的其他普通字段
column:在查询结果集中,数据库的字段名
property:结果集中的数据和失血模型中对应的属性名。
-->
<result column="userName" property="user_name"/>
<result column="pass" property="password"/>
</resultMap>
<!-- 查询所有用户 -->
<select id="queryAllUser" resultMap="userResult">
SELECT user_id id,user_name userName,`password` pass FROM t_user
</select>
动态sql
<!-- 编写一个sql片段,供以后重复使用sql片段 -->
<sql id="query_user_info">
<if test="user.user_name != null">
AND s1.user_name like "%${user.user_name}%"
</if>
<if test="userInfo.gender != null">
AND s2.gender = #{userInfo.gender}
</if>
</sql>
<!-- 使用sql片段 -->
<select id="queryUserAndInfo" parameterType="com.woniuxy.mall.model.UserCustom" resultType="User">
SELECT * FROM t_user as s1 JOIN t_userinfo as s2 on s1.user_id = s2.user_id
<where>
<include refid="query_user_info"></include>
</where>
</select>
一对一、一对多、多对多查询
一对一的关系:人与身份证
Idcard 的代码:
public class Idcard {
private Integer id;
private String code;
public day(Integer id, String code) {
super();
this.id = id;
this.code = code;
}
public day() {
super();
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @return the code
*/
public String getCode() {
return code;
}
/**
* @param code the code to set
*/
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return "day [id=" + id + ", code=" + code + "]";
}
Person 的代码:
public class Person {
private Integer id;
private String name;
private Integer age;
// 个人身份证关联
private Idcard card;
// 省略setter和getter方法
@Override
public String toString() {
return "Person[id=" + id + ",name=" + name + ",age=" + age + ",card="
+ card + "]";
}
}
IdCardMapper.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.dao.IdCardDao">
<select id="selectCodeById" parameterType="Integer" resultType= "com.po.Idcard">
select * from idcard where id=#{id}
</select>
</mapper>
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="com.dao.PersonDao">
<!-- 一对一根据id查询个人信息:级联查询的第一种方法(嵌套查询,执行两个SQL语句)-->
<resultMap type="com.po.Person" id="cardAndPerson1">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<!-- 一对一级联查询-->
<association property="card" column="idcard_id" javaType="com.po.Idcard"
select="com.dao.IdCardDao.selectCodeByld"/>
</resultMap>
<select id="selectPersonById1" parameterType="Integer" resultMap=
"cardAndPerson1">
select * from person where id=#{id}
</select>
<!--对一根据id查询个人信息:级联查询的第二种方法(嵌套结果,执行一个SQL语句)-->
<resultMap type="com.po.Person" id="cardAndPerson2">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<!-- 一对一级联查询-->
<association property="card" javaType="com.po.Idcard">
<id property="id" column="idcard_id"/>
<result property="code" column="code"/>
</association>
</resultMap>
<select id="selectPersonById2" parameterType="Integer" resultMap= "cardAndPerson2">
select p.*,ic.code
from person p, idcard ic
where p.idcard_id=ic.id and p.id=#{id}
</select>
<!-- 一对一根据id查询个人信息:连接查询(使用POJO存储结果)-->
<select id="selectPersonById3" parameterType="Integer" resultType= "com.pojo.SelectPersonById">
select p.*,ic.code
from person p, idcard ic
where p.idcard_id = ic.id and p.id=#{id}
</select>
</mapper>
创建 POJO 类
SelectPersonById 的代码
public class SelectPersonById {
private Integer id;
private String name;
private Integer age;
private String code;
public day() {
super();
}
public day(Integer id, String name, Integer age, String code) {
super();
this.id = id;
this.name = name;
this.age = age;
this.code = code;
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public Integer getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(Integer age) {
this.age = age;
}
/**
* @return the code
*/
public String getCode() {
return code;
}
/**
* @param code the code to set
*/
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return "day [id=" + id + ", name=" + name + ", age=" + age + ", code=" + code + "]";
}
创建数据操作接口:
IdCardDao 的代码
public interface IdCardDao {
public Idcard selectCodeById(Integer i);
}
PersonDao 的代码
public interface PersonDao {
public Person selectPersonById1(Integer id);
public Person selectPersonById2(Integer id);
public SelectPersonById selectPersonById3(Integer id);
}
调用
public class OneToOneController {
@Autowired
private PersonDao personDao;
public void test(){
Person p1 = personDao.selectPersonById1(1);
System.out.println(p1);
System.out.println("=============================");
Person p2 = personDao.selectPersonById2(1);
System.out.println(p2);
System.out.println("=============================");
selectPersonById p3 = personDao.selectPersonById3(1);
System.out.println(p3);
}
}
测试:
public class TestOneToOne {
public static void main(String[] args) {
ApplicationContext appcon = new ClassPathXmlApplicationContext("applicationContext.xml");
OneToOneController oto = (OneToOneController)appcon.getBean("oneToOne-Controller");
oto.test();
}
}
一对多关系:一对多级联查询,用户关联的订单
Orders 类的代码:
public class Orders {
private Integer id;
private String ordersn;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getOrdersn() {
return ordersn;
}
public void setOrdersn(String ordersn) {
this.ordersn = ordersn;
}
@Override
public String toString() {
return "Orders[id=" + id + ",ordersn=" + ordersn + "]";
}
}
创建UserMapper.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.mybatis.mapper.UserMapper">
<!-- 一对多 根据uid查询用户及其关联的订单信息:级联查询的第一种方法(嵌套查询) -->
<resultMap type="com.po.MyUser" id="userAndOrders1">
<id property="uid" column="uid" />
<result property="uname" column="uname" />
<result property="usex" column="usex" />
<!-- 一对多级联查询,ofType表示集合中的元素类型,将uid传递给selectOrdersByld -->
<collection property="ordersList" ofType="com.po.Orders"
column="uid" select="com.dao.OrdersDao.selectOrdersByld" />
</resultMap>
<select id="selectUserOrdersById1" parameterType="Integer"
resultMap="userAndOrders1">
select * from user where uid = #{id}
</select>
<!--对多根据uid查询用户及其关联的订单信息:级联查询的第二种方法(嵌套结果) -->
<resultMap type="com.po.MyUser" id="userAndOrders2">
<id property="uid" column="uid" />
<result property="uname" column="uname" />
<result property="usex" column="usex" />
<!-- 对多级联查询,ofType表示集合中的元素类型 -->
<collection property="ordersList" ofType="com.po.Orders">
<id property="id" column="id" />
<result property="ordersn" column="ordersn" />
</collection>
</resultMap>
<select id="selectUserOrdersById2" parameterType="Integer"
resultMap="userAndOrders2">
select u.*,o.id, o.ordersn from user u, orders o where u.uid
= o.user_id and
u.uid=#{id}
</select>
<!-- 一对多 根据uid查询用户及其关联的订单信息:连接查询(使用POJO存储结果) -->
<select id="selectUserOrdersById3" parameterType="Integer"
resultType="com.pojo.SelectUserOrdersById">
select u.*, o.id, o.ordersn from user u, orders o where
u.uid = o.user_id
and u.uid=#{id}
</select>
</mapper>
创建:OrdersMapper.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.dao.OrdersDao">
<!-- 根据用户uid查询订单信息 -->
<select id="selectOrdersById" resultType="com.po.Orders"
parameterType="Integer">
select * from orders where user_id=#{id}
</select>
</mapper>
创建 POJO 类
SelectUserOrdersById代码:
public class SelectUserOrdersById {
private Integer uid;
private String uname;
private String usex;
private Integer id;
private String ordersn;
// 省略setter和getter方法
@Override
public String toString() { // 为了方便查看结果,重写了toString方法
return "User[uid=" + uid + ",uname=" + uname + ",usex=" + usex
+ ",oid=" + id + ",ordersn=" + ordersn + "]";
}
}
创建数据操作接口
public interface OrdersDao {
public List<Orders> selectOrdersById(Integer uid);
}
public interface UserDao {
public MyUser selectOrdersById1(Integer uid);
public MyUser selectOrdersById2(Integer uid);
public List<SelectUserOrdersById> selectOrdersById3(Integer uid);
}
调用接口方法
public void test(){
//查询一个用户及订单信息
MyUser auser1 = userDao.selectUserOrderById1(1);
System.out.println(auser1);
System.out.println("=============================");
MyUser auser2 = userDao.selectUserOrderById2(1);
System.out.println(auser2);
System.out.println("=============================");
List<SelectUserOrdersById> auser3 = userDao.selectUserOrdersById3(1);
System.out.println(auser3);
System.out.println("=============================");
}
测试:
public class TestOneToMore {
public static void main(String[] args) {
ApplicationContext appcon = new ClassPathXmlApplicationContext("applicationContext.xml");
OneToMoreController otm = (OneToMoreController)appcon.getBean("oneToMoreController");
otm.test();
}
}
多对多的关系:订单和商品
Product 的代码:
public class Product {
private Integer id;
private String name;
private Double price;
public day() {
super();
}
public day(Integer id, String name, Double price) {
super();
this.id = id;
this.name = name;
this.price = price;
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the price
*/
public Double getPrice() {
return price;
}
/**
* @param price the price to set
*/
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "day [id=" + id + ", name=" + name + ", price=" + price + "]";
}
Orders 的代码:
public class Orders {
private Integer id;
private String ordersn;
public day() {
super();
}
public day(Integer id, String ordersn) {
super();
this.id = id;
this.ordersn = ordersn;
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @return the ordersn
*/
public String getOrdersn() {
return ordersn;
}
/**
* @param ordersn the ordersn to set
*/
public void setOrdersn(String ordersn) {
this.ordersn = ordersn;
}
@Override
public String toString() {
return "day [id=" + id + ", ordersn=" + ordersn + ", getId()=" + getId() + ", getOrdersn()=" + getOrdersn()
+ ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()=" + super.toString()
+ "]";
}
在 Orders 接口中添加以下接口方法:
public List
调用接口方法
public class MoreToMoreController {
@Autowired
private OrdersDao ordersDao;
public void test() {
List<Orders> os = ordersDao.selectallOrdersAndProducts();
for (Orders orders : os) {
System.out.println(orders);
}
}
}
测试:
public class TestMoreToMore {
public static void main(String[] args) {
ApplicationContext appcon = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MoreToMoreController otm = (MoreToMoreController) appcon
.getBean("moreToMoreController");
otm.test();
}
}
延迟加载、一级缓存和二级缓存
什么是延迟加载
resultMap中的association和collection标签具有延迟加载的功能。
延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。使用关联信息时再去加载关联信息
设置延迟加载
需要在SqlMapConfig.xml文件中,在
lazyLoadingEnabled、aggressiveLazyLoading
<!-- 开启延迟加载 -->
<settings>
<!-- lazyLoadingEnabled:延迟加载启动,默认是false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- aggressiveLazyLoading:积极的懒加载,false的话按需加载,默认是true -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 开启二级缓存,默认是false -->
<setting name="cacheEnabled" value="true"/>
</settings>
Mybatis的一级缓存是指SqlSession。一级缓存的作用域是一个SqlSession。Mybatis默认开启一级缓存。
在同一个SqlSession中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则SqlSession的缓存清空。
Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
在同一个namespace下的mapper文件中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则二级缓存清空。
一级缓存:
二级缓存: