MyBatis介绍
- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
MyBatis 本是 apache 的一个开源项目iBatis, 2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。2013 年 11 月迁移到 Github。
MyBatis完成数据访问层的优化.它专注于sql语句.简化了过去JDBC繁琐的访问机制.
怎么获取mybatis?
maven仓库
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
搜搜jar包的坐标网站:https://mvnrepository.com/
mybatis中文文档:https://mybatis.net.cn/
MyBatis快速入门
添加所需依赖
修改pom.xml文件,添加MyBatis需要的依赖
<dependencies>
<!-- 添加mybatis框架依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- 添加mysql依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
</dependencies>
指定资源文件
修改pom.xml文件,指定资源文件(保证目录中的所有资源文件都拷贝到target中)
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
添加配置文件
jdbc.properties文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8
#jdbc.url=jdbc:mysql://localhost:3308/ssm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=root
添加核心配置文件(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">
```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">
<environments default="development">
<environment id="development">
<!--配置事务管理器
type:指定事务管理的方式
JDBC:事务的控制交给程序员处理
MANAGED:由容器(如:Spring)来管理事务
注意:这里的type值必须大写
-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源
type:指定不同的配置方式
JNDI:java命名目录接口,在服务器端进行数据库连接池的管理(一般不使用)
POOLED:使用数据库连接池
UNPOOLED:不使用数据库连接池
-->
<dataSource type="POOLED">
<!--配置数据库连接的四个参数-->
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="StudentMapper.xml"></mapper>
</mappers>
- 添加StudentMapper.xml文件
```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">
<?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:是整个文件的大标签,用来开始和结束xml文件
属性:namespace:指定命名空间(相当于包名),用来区分不同mapper.xml文件中相同的id属性
-->
<mapper namespace="xs">
<!--使用JDBC原始方式查询全部学生的方式:List<Student> selectAll();
resultType:指定查询返回的结果集的类型,如果是集合,则必须是泛型的类型
parameterType:如果有参数,则通过它来指定参数的类型(使用别名,查看别名映射表)
-->
<select id="selectAll" resultType="com.ityg.pojo.Student">
select id,name,email,age
from student
</select>
<!--
按主键id查询学生信息
Student getAllById(Integer id);
-->
<select id="getAllById" resultType="com.ityg.pojo.Student" parameterType="int">
select id,name ,email,age
from student
where id = #{id}
</select>
</mapper>
junit测试
student为基本的JavaBean实体类。
public class test {
@Test
public void testSelectAll(){
InputStream in = null;
SqlSessionFactory factory = null;
SqlSession sqlSession = null;
try {
//1.使用文件流读取核心配置文件(SqlMapConfig.xml)
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
factory = new SqlSessionFactoryBuilder().build(in);
//3.获取sqlSession对象
sqlSession = factory.openSession();
//4.完成查询操作
List<Object> list = sqlSession.selectList("selectAll");
list.forEach(student -> System.out.println(student));
} catch (IOException e) {
e.printStackTrace();
}finally {
//5.关闭sqlSession
if (sqlSession!=null) {
sqlSession.close();
}
}
}
}
为实体类注册别名
单个注册
<typeAliases>
<typeAlias type="com.ityg.pojo.Student" alias="student"></typeAlias>
</typeAliases>
/*
type:实体类的全限定名
alias:别名
*/
批量注册
<package name="com.ityg.pojo"></package>
//name:实体类的包路径
//别名为类名的驼峰命名法
设置日志输出
<!--设置日志输出底层执行的代码
name和value就设置这两个值
-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
注意标签的书写位置(顺序) properties, settings, typeAliases, environments, mappers(依次从上到下)
使用动态代理
动态代理存在的意义:在三层架构中,业务逻辑层需要通过接口访问数据库访问层的功能。然而使用了MyBatis框架,无法在业务逻辑层访问xml文件中的功能。
动态代理可以实现。
动态代理的规范
- UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下.
- UsersMapper.xml文件与UsersMapper.java的接口的文件名必须一致,后缀不管.
- UserMapper.xml文件中标签的id值与与UserMapper.java的接口中方法的名称完全一致.
- UserMapper.xml文件中标签的parameterType属性值与与UserMapper.java的接口中方法的参数类型完全一致.
- UserMapper.xml文件中标签的resultType值与与UserMapper.java的接口中方法的返回值类型完全一致.
- UserMapper.xml文件中namespace属性必须是接口的完全限定名称com.ityg.mapper.UsersMapper
- 在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称com.ityg.mapper.UsersMapper.(一般使用package方式注册
)
使用动态代理访问CRUD操作步骤:
- 创建数据表(Users)
- 新建maven工程 ,修改目录,添加实体类
- 修改pom.xml文件,添加依赖
- 添加jdbc.propertis文件到resources目录下
- 添加SqlMapConfig.xml(MyBatis核心配置)文件
- 添加mapper文件夹,新建UsersMapper接口
- 在mapper文件夹下,新建UsersMapper.xml文件,完成增删改查功能
- 添加测试类,测试功能
代码实现:
这里从第5步开始
5-创建MyBatis核心配置文件
<?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>
<!--1.读取属性文件 jdbc.properties-->
<properties resource="jdbc.properties"></properties>
<!--2.设置控制台日志输出-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--3.给实体类注册别名-->
<typeAliases>
<!--为该目录下所有实体自动注册别名-->
<package name="com/ityg/pojo"/>
</typeAliases>
<!--4.配置数据库环境变量-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--5.注册mapper.xml文件-->
<mappers>
<!--注意这里使用类的全限定名,打点的方式-->
<!--<mapper class="com.ityg.mapper.UsersMapper"></mapper>-->
<!--批量注册-->
<package name="com.ityg.mapper"/>
</mappers>
</configuration>
6-创建业务接口(UsersMapper接口)
public interface UsersMapper {
//查询所有用户
List<Users> getAll();
//根据主键查询用户
Users getById(int id);
//根据用户名模糊查询
List<Users> getByName(String name);
//用户的更新
int update(Users users);
//增加用户
int insert(Users users);
//根据主键删除用户
int delete(int id);
}
7-创建执行业务操作的xml配置文件(UsersMapper.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.ityg.mapper.UsersMapper">
<!-- //查询所有用户
List<Users> getAll();
-->
<select id="getAll" resultType="users">
select id,username,birthday,sex,address from users
</select>
<!--//根据主键查询用户
Users getUserById(int id);-->
<select id="getUserById" parameterType="int" resultType="users">
select id,username,birthday,sex,address from users
where id=#{id}
</select>
<!--//根据用户名模糊查询
List<Users> getByName(String name);-->
<select id="getByName" parameterType="string" resultType="users">
select id,username,birthday,sex,address from users where username like '%${name}%'
</select>
<!-- //用户的更新
int update(Users users);
private Integer id;
private String userName;
private Date birthday;
private String sex;
private String address;-->
<update id="update" parameterType="users">
update users set username=#{userName},birthday=#{birthday},sex=#{sex},address=#{address}
where id=#{id}
</update>
<!--//增加用户
int insert(Users users);-->
<insert id="insert" parameterType="users">
insert into users(username,birthday,sex,address)
values(#{userName},#{birthday},#{sex},#{address})
</insert>
<!--//根据主键删除用户
int delete(int id);-->
<delete id="delete" parameterType="int" >
delete from users where id=#{id}
</delete>
</mapper>
8-测试
public class mapperTest {
SqlSession sqlSession = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//取出动态代理的对象,完成接口中方法的调用,实则是调用xml文件中的相应标签的功能
UsersMapper mapper = null;
@Before
public void openSqlSession() throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
sqlSession = factory.openSession();
mapper = sqlSession.getMapper(UsersMapper.class);
}
@After
public void closeSqlSession(){
sqlSession.close();
}
@Test
public void testGetUserById(){
//取出动态代理的对象,完成接口中方法的调用,实则是调用xml文件中的相应标签的功能
UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
Users user = usersMapper.getById(8);
System.out.println(user);
}
@Test
public void testUpdate() throws ParseException {
Users user = new Users(7,"haha",sdf.parse("2000-01-01"),"1","十堰");
int count = mapper.update(user);
System.out.println(count);
//切记切记切记,增删改 必须要手工提交事务
sqlSession.commit();
}
@Test
public void testInsert() throws IOException, ParseException {
mapper.insert(new Users("heeh",sdf.parse("2022-01-02"),"2","武汉"));
sqlSession.commit();
}
@Test
public void testDelete(){
int i = mapper.delete(27);
System.out.println(i);
sqlSession.commit();
}
}
优化mapper.xml文件注册
<!--注册mapper.xml文件-->
<mappers>
<!--绝对路径注册-->
<mapper url="/////"></mapper>
<!--非动态代理方式下的注册
UsersMapper.xml文件放在resource目录下
-->
<mapper resource="UsersMapper.xml"></mapper>
<!--动态代理方式下的单个mapper.xml文件注册-->
<mapper class="com.ityg.mapper.UsersMapper"></mapper>
<!--批量注册-->
<package name="com.ityg.mapper"></package>
</mappers>
#{}:占位符,${}:字符串拼接或替换
传参时大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问 ,防止sql注入.
{}里如何写,看parameterType参数的类型
1)如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里随便写 2)parameterType的类型是实体类的类型,则#{}里只能是类中成员变量的名称,而且区分大小写.
- ${}字符串拼接或字符串替换
字符串拼接,一般用于模糊查询中.建议少用,因为有sql注入的风险.
- 如果parameterType的类型是简单类型,则${}里随便写,但是分版本,如果是3.5.1及以下的版本,只以写value
- 如果parameterType的类型是实体类的类型,则${}里只能是类中成员变量的名称.(现在已经少用)
优化后的模糊查询(以后都要使用这种方式)
parameterType属性
- 如果是一个参数需要写
- 如果是两个参数,则不写
@Param()的使用
字符串替换
需求:模糊地址或用户名查询(根据传入的参数,动态的执行是按用户名还是地址进行模糊查询) select from users where username like ‘%小%’; select from users where address like ‘%市%’
//为参数添加注解
List<Users> getByNameOrAddress(
@Param("columnName") String columnName,
@Param("columnValue") String columnValue);
<!-- 此处使用的是@Param注解里的名称
where ${columnName}:这里也还存在sql注入问题
没有弄明白
-->
<select id="getByNameOrAddress" parameterType="string" resultType="users">
select id,username,birthday,sex,address from users
where ${columnName} like concat('%',#{columnValue },'%')
</select>
如果参数超过一个,则parameterType不写
返回当前插入数据的主键
需要在insert标签中加入下面代码
select last_insert_id();
标签的参数详解: keyProperty: 实体类对象(users)的哪个属性来接返回的主键值 resultType:返回的主键的类型 order:在插入语句执行前,还是执行后返回主键的值
<!--//增加用户
int insert(Users users);-->
<insert id="insert" parameterType="users">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into users(username,birthday,sex,address)
values(#{userName},#{birthday},#{sex},#{address})
</insert>
UUID(生成全球唯一随机字符串)
@Test
public void testUuid(){
UUID uuid = UUID.randomUUID();
System.out.println(uuid.toString());
}
动态sql
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
和标签
:当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为常量,方便调用。 :引用 中定义的常量。 <!-- 定义代码片段-->
<sql id="allColumn">
id,username,birthday,sex,address
</sql>
<select id="getAll" resultType="users">
select
-- 引用定义的代码片段
<include refid="allColumn"></include>
from users
</select>
和 标签 :进行条件判断,test条件判断的取值可以是实体类的成员变量,可以是map的key,可以是@Param注解的名称。 :进行多条件拼接,在查询,删除,更新中使用,一般开发复杂业务的查询条件时,如果有多个查询条件,通常会使用 标签来进行控制。标签可以自动的将第一个条件前面的逻辑运算符 (or ,and) 去掉。 <!--根据User给的属性,进行模糊查询
List<Users> getByCondition(Users users);
-->
<select id="getByCondition" parameterType="users" resultType="users">
select <include refid="allColumn"></include> from users
<where>
<if test="userName != null and userName != ''">
and username like concat('%',#{userName},'%')
</if>
<if test="birthday != null">
and birthday = #{birthday}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
<if test="address != null and address != ''">
and address like concat('%',#{address},'%')
</if>
</where>
</select>
注意每一个if里面的语句前面需要加一个and
标签
使用set标签可以将动态的配置 SET 关键字,并剔除追加到条件末尾的任何不相关的逗号。使用 if+set 标签修改后,在进行表单更新的操作中,哪个字段中有值才去更新,如果某项为 null 则不进行更新,而是保持数据库原值。切记:至少更新一列。
<!-- 根据user的属性值有无来更新
int updateBySet(Users users);
-->
<update id="updateBySet" parameterType="users">
update users
<set>
<if test="userName != null and userName != ''">
username = #{userName},
</if>
<if test="birthday != null">
birthday = #{birthday},
</if>
<if test="sex != null and sex != ''">
sex = #{sex},
</if>
<if test="address != null and address != ''">
address = #{address},
</if>
</set>
where id = #{id}
</update>
注意每个if里面的语句后面需要加一个’,’逗号
标签
主要用来进行集合或数组的遍历,主要参数有:
- collection:接受过来的参数,属性值有list,array,map;它们对应的参数类型分别是:List,数组,Map集合
- item:循环体的具体对象,支持属性的点路径访问,如item.age,item.info.details,在list和数组中是其中的对象,在map中是value。
- separator:表示元素之间的分隔符,例如在in()的时候,separator=”,”会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。
- open:表示该语句以什么开始
- close:表示该语句以什么结束
- index:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。
循环遍历参数集合
<!-- //查询所有id查
List<Users> getByIds(int[] array);
-->
<select id="getByIds" resultType="users">
select
<include refid="allColumn"></include>
from users where id in<!--(
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>
)-->
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
批量增加
<!--//批量增加
int insertBatch(List<Users> users);-->
<insert id="insertBatch" parameterType="users">
insert into users(username,birthday,sex,address) values
<foreach collection="list" item="user" separator=",">
(#{user.userName},#{user.birthday},#{user.sex},#{user.address})
</foreach>
</insert>
批量删除
<!--//批量删除
int deleteBeach(int[] array);-->
<delete id="deleteBeach">
delete from users where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
批量更新
注意:要使用批量更新,必须在jdbc.properties属性文件中的url中添加 &allowMultiQueries=true,允许多行操作。<!--//批量更新
int updateBeach(List<Users> users);-->
<update id="updateBeach">
<foreach collection="list" item="user" separator=";">
update users
<set>
<if test="user.userName != null and user.userName != ''">
username = #{user.userName},
</if>
<if test="user.birthday != null">
birthday = #{user.birthday},
</if>
<if test="user.sex != null and user.sex != ''">
sex = #{user.sex},
</if>
<if test="user.address!= null and user.address != ''">
address = #{user.address},
</if>
</set>
where id = #{user.id}
</foreach>
</update>
参数问题
指定参数位置
可以不使用对象的属性名进行参数值绑定,使用下标值
<!--//查询指定出生日期区间的
List<Users> getBirthday(Date begin,Date end);-->
<select id="getBirthday" resultType="users">
select <include refid="allColumn"></include>
from users
where birthday between #{arg0} and #{arg1}
</select>
@Param 指定参数名称
UserMapper.java接口:
//切换列名进行模糊查询
//@Param("columnName"):这里定义的columnName的名称是要在xml文件中的${引用定义的名称}
//为参数添加注解
List<Users> getByNameOrAddress(
@Param("columnName") String columnName,
@Param("columnValue") String columnValue);
UserMapper.xml中:
<select id="getByNameOrAddress" parameterType="string" resultType="users">
select <include refid="allColumn"></include> from users
where ${columnName} like concat('%',#{columnValue },'%')
</select>
入参是map
入参是map,是因为当传递的数据有多个,不适合使用指定下标或指定名称的方式来进行传参,又加上参数不一定与对象的成员变量一致,考虑使用map集合来进行传递.map使用的是键值对的方式.当在sql语句中使用的时候#{键名},${键名},用的是键的名称.
<!-- //入参是map
List<Users> getByMap(Map<String,Date> map);-->
<select id="getByMap" resultType="users">
select <include refid="allColumn"></include>
from users
where birthday between #{birthdayBegin} and #{birthdayEnd}
</select>
返回值是map
<!--//返回值是map一行-->
<!--Map<String,Object> getReturnMap(Integer id);-->
<select id="getReturnMap" resultType="map" parameterType="int">
select username,address
from users where id = #{id}
</select>
<!--//返回值是map多行
List<Map<String,Object>> getMulMap();-->
<select id="getMulMap" resultType="map">
select username,address
from users
</select>
列名与类中成员变量名不一致问题
- 解决方法一:使用列的别名,别名与类中的成员变量名一样,即可完成注入。
-
表的关联关系
总结:无论是什么关联关系,如果某方持有另一方的集合,则使用
标签完成映射,如果某方持有另一方的对象,则使用 标签完成映射。 一对一关系
一对多关系
<?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.ityg.mapper.CustomerMapper">
<!--//根据客户id查询客户信息以及该客户的所有订单
Customer getCustomerById(int id);
实体类的属性:
private Integer id;
private String name;
private Integer age;
//该客户名下的所有订单的集合
private List<Order> orders;
-->
<resultMap id="cmap" type="customer">
<!--主键绑定-->
<id property="id" column="cid"></id>
<!--非主键绑定-->
<result property="name" column="name"></result>
<result property="age" column="age"></result>
<!--其他实体的部分orders
private Integer id;
private String num;
private double price;
-->
<collection property="orders" ofType="order">
<id property="id" column="oid"></id>
<result property="num" column="orderNumber"></result>
<result property="price" column="orderPrice"></result>
</collection>
</resultMap>
<select id="getCustomerById" parameterType="int" resultMap="cmap">
select c.id cid,name,age,o.id oid,orderNumber,orderPrice,customer_id
from customer c left join orders o on c.id=o.customer_id
where c.id = #{id}
</select>
</mapper>
多对一关系
<?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.ityg.mapper.OrderMapper">
<!--//根据订单id查询订单以及该订单的客户
Order getOrderById(int id);
实体类属性
private Integer id;
private String num;
private double price;
//关联下此订单的客户信息,多方持有一方的对象
private Customer customer;
-->
<resultMap id="omap" type="order">
<id property="id" column="oid"></id>
<result property="num" column="orderNumber"></result>
<result property="price" column="orderPrice"></result>
<association property="customer" column="customer">
<id property="id" column="cid"></id>
<result property="name" column="name"></result>
<result property="age" column="age"></result>
</association>
</resultMap>
<select id="getOrderById" parameterType="int" resultMap="omap">
select o.id oid,orderNumber,orderPrice,c.id cid,name,age
from orders o inner join customer c on customer_id = c.id
where o.id = #{id}
</select>
</mapper>
多对多关系
事务
ORM
ORM(Object Relational Mapping):对象关系映射
编写程序的时候,以面向对象的方式处理数据,保存数据的时候,却以关系型数据库的方式存储。
持久化的操作:将对象保存到关系型数据库中,将关系型数据库中的数据读取出来以对象的形式封装