【整理】MyBatis
此处只讲重点的内容,详细讲解请到此。
Day_01:入门
1、快速入门
1)执行步骤
-
①添加MyBatis的坐标
-
②创建user数据表
-
③编写User实体类
-
④编写映射文件UserMapper.xml 【用于配置SQL语句】
-
⑤编写核心文件SqlMapConfig.xml 【配置Mybatis核心配置】
-
⑥编写测试类
④编写映射文件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="userMapper"> //命名空间(这里不使用框架生成的代理对象,所以这个是自定义的)
<!--改-->
<update id="update" parameterType="com.itheima.domain.User"> //parameterType:你要传入参数的全限定名。(可以使用自定义别名或Spring提供的别名代替)
update user set username = #{username},password =#{password} where id = #{id} //#{xxx}:是传入参数的属性(Mybatis根据属性名称自动映射),要和数据库顺序一样。
</update>
⑤编写核心文件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">
内容:
<!--2、数据库环境-->
<configuration>
<environments default="development"> 【配置默认使用的环境是xxx】
<environment id="development"> 【给这个环境取个名:development】
<transactionManager type="JDBC"/> 【使用JDBC的事务管理器(transactionManage)】
<!--配置数据源数据-->
<dataSource type="POOLED"> 【数据源类型:池子(池子化类型)】
<property name="driver" value="com.mysql.jdbc.Driver"/> 【name是属性(属性固定)】
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--3、加载映射文件-->
<mappers>
<mapper resource="com/itheima/mapper/UserMapper.xml"/>
</mappers>
</configuration>
关于加载映射文件的另一种方式:
扫mapper配置文件的包名,加载所有配置文件,不用一个一个的添加了:
<mapper>
<package name ="com.itheima.mapper"/>
</mapper>
映射文件一定要加载映射关系,不然SQL没有功能。
⑥编写测试类
@Test
public void Demo04() throws IOException {
//模拟:封装好数据的实体类
User user = new User();
user.setId(6);
user.setUsername("张学友");
user.setPassword("abc");
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获取SqlSessionFactory对象
SqlSessionFactory SqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession会话对象
SqlSession sqlSession = SqlSessionFactory.openSession();
//执行SQL
sqlSession.insert("userMapper.update",user);//命名空间.id
//提交事务
sqlSession.commit();//Mybatis默认不提交事务
//释放资源
sqlSession.close();
}
2)Mybatis核心配置文件:概述
①environments标签
②mapper标签
③Properties
在核心配置文件上配置
<!--加载jdbc配置文件-->
<properties resource="jdbc.properties"/>
<!--数据源环境-->
<environments default="develoment">
<environment id="develoment">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
④typeAliaser
我们会发现如果每次配置SQL语句指定参数类型的时候,都要填写全类名,这样太繁琐了。
我们可以配置typeAliaser
标签,指定某个类是某个别名
来进进行代替。
Mybatis提供的别名我们不需要自行配置,但是,自定义的类需要自己必须要配置。
核心配置文件:
<configuration>
<!--加载jdbc配置文件-->
<properties resource="jdbc.properties"/>
【注意标签顺序】
<!--自定义别名-->
<!--方式1:指定具体某个类-->
<typeAliases>
<typeAlias type="com.itheima.domain.User" alias="user"/>
</typeAliases>
<typeAliases>
<!--方式2:扫包-->
<package name="com.itheima.domain"/>
</typeAliases>
`
映射文件:
<!--删-->
<delete id="delete" parameterType="int">
delete from user where id = #{id} <!--因为唯一,名称随意-->
</delete>
<!--改-->
<update id="update" parameterType="user">
update user set username = #{username},password =#{password} where id = #{id}
</update>
注意:配置typeAliases一定要注意配置标签之间的顺序(其他也要遵守)
3)MyBatis相关API
①SqlSessionFactoryBuilder工厂构建对象
②SqlSessionFactory工厂对象
工厂对象专门制造对象的。
③SqlSession会话对象(重要)
Day_02:
一、Dao层实现原理
1)代理开发方式
以前我们使用dao层,自己要写dao接口和dao实现类,但是Mybatis可以只有接口(类似dao),没有实现;实现实际上是动态代理对象,框架帮我生成
这个”全限定名还没改↓”
(xml配置的namespace = 接口的全限定名)
代码实现:
①配置Mapper
<mapper namespace="com.itheima.dao.UserMapper"> //接口全限定名
<!--查询所有User(无参)-->
<select id="findAll" resultType="user">
select * from USER
</select>
<!--根据id查询User(参数int id)-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
②定义接口
public interface UserMapper {
public List<User> findAll() throws IOException;
public User findById(int id);
}
③测试代码
public class Demo01 {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//执行SQL
List<User> userList = mapper.findAll();
//执行SQL、
User user = mapper.findById(1);
System.out.println(userList);System.out.println(user);
//释放资源
sqlSession.close();
}
}
2)Mybatis映射文件深入:动态SQL
1)if(重要)
业务场景:用于筛选条件操作数据库,条件不确定
可能1个,可能多个,可能没有
select * from user
select * from user where id=?
select * from user where id=? and username=?
select * from user where id=? and username =? and password=?
Mapper配置文件
<mapper namespace="com.itheima.dao.UserMapper">
<select id="findByConditon" resultType="user" parameterType="user">
select * from USER
<where>
<if test="id!=0">
and id = #{id}
</if>
<if test="username!=null"> //属性名称
and username = #{username}
</if>
<if test="password!=null">
and password = #{password}
</if>
</where>
</select>
<where>附加条件</where>
如果附加条件不满足就不进行SQL语句拼接,如果全部满足<where>标签以及标签内等于没有
2)foreach
业务场景:循环执行sql的拼接操作
select * from user where id = 1 or id = 2 ,id =3:在1-3之内查询: 有什么就查什么,没有就不查询:
等于
select * from user id in(1,2,3)因此在( )之内,也是动态的,不确定的。
Mapper配置文件
<mapper namespace="com.itheima.dao.UserMapper">
<select id="findByIds" parameterType="list" resultType="user">
select * from user <!--where id in (1,2,3)-->
<where>
<foreach collection="list" open="id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
解析:
- parameterType=“list”:list是框架定义好的别名
- collection:翻译“集合”,这里填你传入参数的类型,(可以填集合,也可以填数组(数组填“arrays”))
- open:从哪里开始
- close:从哪里结束
- item:翻译“项”,意思是从collection中取出的每一项的值
- separator:分隔符
select * from user where id in(1,2,3) = select * from user where “open + item + separator + close”
3)抽取重复的sql
抽取:<sql id=“selectUser”>select * from user</sql>
引入:<include refid=“selectUser”></include>
Mapp配置文件
二、Mybatis核心配置文件深入
1)typeHandlers标签
类型转换器,java数据类型
转 数据库的数据类型
,或者 数据库数据类型
转 java数据类型
。
如果要特将某个java类型
能够转数据库数据类型
就要自定义,下面是预处理器
帮我们转换的。
下面使用代码的形式解析:
目的:将java的Date类型
存进 数据库bigint数据类型
中;操作数据库时,将返回bigint类型的数据
又转回成 Date类型
,返回给java
解决:定义一个类型转换器
:将Date类型数据
转换成毫秒值的类型
存进数据库中;数据库返回时,又将 毫秒值
转Date
①数据库:
②自定义转换器:继承BaseType<T>
③复写4个方法
public class DateTpyeHandler extends BaseTypeHandler<Date> {//<T>:T为你要转换的数据类型
//将java类型 转换成 数据库字段的数据类型
@Override //int i:为Date参数的位置(执行SQL中传入的参数位置)
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
//将Date转换成毫秒值
long time = date.getTime();
//设置参数,设置要转换的毫秒值
preparedStatement.setLong(i,time);
}
//将数据库字段数据类型 转换成 java类型
//String:需要转换数据类型的字段名称
//ResultSet:数据库查询出来的结果集
@Override
public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
//获取结果集中需要转换的数据类型(long)
long aLong = resultSet.getLong(s);
//转换成Date类型
Date date = new Date(aLong);
return date;
}
//将数据库字段数据类型 转换成 java类型
//int i:需要转换数据类型的字段位置
@Override
public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
//获取结果集中需要转换的数据类型(long)
long aLong = resultSet.getLong(i);
//转换成Date类型
Date date = new Date(aLong);
return date;
}
//将数据库字段数据类型 转换成 java类型
//int i:需要转换数据类型的字段位置
@Override
public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
//从CallableStatement中获取需要转换的数据类型(long)
long aLong = callableStatement.getLong(i);
//转换成Date类型
Date date = new Date(aLong);
return date;
}
}
④MyBatis中注册转换器
注意配置与配置之间的 配置顺序
<!--注册类型转换器-->
<typeHandlers>
<typeHandler handler="com.itheima.handler.DateTpyeHandler"/>
</typeHandlers>
⑤测试
Mapper配置:
<mapper namespace="com.itheima.dao.UserMapper">
<sql id="selectUser">select * from user</sql>
<!--插入数据:测试java类型转数据库类型数据-->
<insert id="save" parameterType="user">
insert into user values (#{id},#{username},#{password},#{birthday})
</insert>
<!--查询数据:测试数据库转java类型数据-->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
测试类:
//数据库转java类型数据
@org.junit.Test
public void Demo03() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//执行SQL
User user = mapper.findById(10);
System.out.println(user);
sqlSession.close();
}
//java转数据库类型数据
@org.junit.Test
public void Demo04() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//模拟封装好请求参数的user
User user = new User();
user.setUsername("刘德华");
user.setPassword("123");
user.setBirthday(new Date());
//执行SQL
mapper.save(user);
System.out.println(user);
sqlSession.close();
}
2)plugins标签
plugins(插件)可以导入插件拓展Mybatis功能,下面 演示分页插件的功能
①pom.xml:导入分页插件
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>
②Mybatis核心配置文件:配置分页插件
<!--配置分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/> <!--指定方言:(指定什么数据库)因为不同数据库sql命令可能不一样-->
</plugin>
</plugins>
③测试
@org.junit.Test
public void Demo05() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//设置分页相关参数 参数(当前页码,每页显示条数)
PageHelper.startPage(1,3);//显示第1页的3条数据
//执行SQL
List<User> users = mapper.findAll();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
分页插件:获取其他相关参数
@org.junit.Test
public void Demo05() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
//设置分页相关参数 参数(当前页码,每页显示条数)
PageHelper.startPage(2,3);//显示第1页的3条数据
//执行SQL
List<User> users = mapper.findAll();//查询所有user
for (User user : users) {
System.out.println(user);
}
//获取分页相关的参数
PageInfo<User> info = new PageInfo<User>(users);//<T>:你要进行分页的Bean对象 参数:返回查询user的集合
System.out.println("当前页码:"+info.getPageNum());
System.out.println("每页显示条数:"+info.getPageNum());
System.out.println("总条数:"+info.getTotal());
System.out.println("总页码:"+info.getPages());
System.out.println("上一页:"+info.getLastPage());
System.out.println("下一页:"+info.getNextPage());
System.out.println("第一页:"+info.getFirstPage());
System.out.println("最后一个:"+info.getLastPage());
System.out.println("是否为第一页:"+info.isIsFirstPage());
System.out.println("是否为最一页:"+info.isIsLastPage());
//....
sqlSession.close();//释放资源
}
知识小结
Day_03:多表查询
此处为了简洁,将省去测试类,只放重点。如果想详细,请点击此处。
环境搭建:
数据库
sqlMapCongfig.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>
<!--加载jdbc配置文件-->
<properties resource="jdbc.properties"/>
<!--自定义别名-->
<typeAliases>
<typeAlias type="com.itheima.domain.User" alias="user" />
<typeAlias type="com.itheima.domain.Order" alias="order" />
</typeAliases>
<!--注册类型转换器-->
<typeHandlers>
<typeHandler handler="com.itheima.handler.DateTpyeHandler"/>
</typeHandlers>
<!--配置分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/> <!--指定方言:(指定书目数据库)因为不同数据库sql命令可能不一样-->
</plugin>
</plugins>
<!--搭建数据源环境-->
<environments default="develoment">
<environment id="develoment">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<mapper resource="com/itheima/mapper/UserMapper.xml"/>
<mapper resource="com/itheima/mapper/OrderMapper.xml"/>
</mappers>
</configuration>
关于自定义别名:
【还有1中自定义别名的方式是:扫包】
<!--自定义别名-->
<typeAliases>
<package name = "com.iiheima.domain"/>
【扫实体类的包,它会将包下的所有实体类都定义别名,别名为该实体类名称的首字母小写。】
实体类:User&Order(订单)
public class User {
private int id;
private String username;
private String password;
//忽略get、set方法和toString
}
public class Order {
private int id;
private Date orderTime;//下单时间
private double total;//订单价格
private User user; //当前订单属于哪个客户
//忽略get、set方法和toString
一、XML配置方式:
1)一对一
问题: 单单查询Order表是不能够查询出来User的,因为Order表中没有User类型的字段,只有1个相关的uid。
铺垫:
先让order表和user表结合成1个表:内连接查询
SELECT * , o.id oid FROM orders o , USER u WHERE u.id = o.id
解决:
手动指定:字段名与实体类属性的映射关系
(将查询结果集的字段 映射到 实体类的属性中)
①OrderMapper接口
public interface OrderMapper {
List<Order> findAll();
}
②OrderMapper.xml
<mapper namespace="com.itheima.mapper.OrderMapper">
<!--
【手动指定:字段名与实体类属性的映射关系 (将查询结果集的字段映射到实体类的属性中)】
type:你要封进的实体类
column:数据库字段名称 (id:表示 主键 result:表示 普通字段 【都是返回查询结果的字段】)
property:实体类属性
-->
<resultMap id="orderMap" type="order"> <!--order自定义别名(全限定名)-->
//Order的简单属性
<id column="oid" property="id"/> <!--数据库的oid 对应着 实体类属性的id-->
<result column="orderTime" property="orderTime"/>
<result column="total" property="total"/>
<result column="uid" property="user.id"/>
<result column="username" property="user.username"/>
<result column="password" property="user.password"/>
<result column="birthday" property="user.birthday"/>
</resultMap>
<select id="findAll" resultMap="orderMap"> <!--resultMa:指定哪个结果映射的id标识-->
SELECT * , o.id oid FROM orders o , USER u WHERE u.id = o.uid
</select>
</mapper>
映射过程
映射原理
Mapper的第二种配置:
OrderMapper.xml:
<resultMap id="orderMap" type="order"> <!--自定义别名-->
//Order的简单属性
<id column="oid" property="id"/> <!--数据库的oid 对应着 实体类属性的id-->
<result column="orderTime" property="orderTime"/>
<result column="total" property="total"/>
//Order的User集合属性
<!--
association :翻译“匹配”
property:表示实体类(order)的属性名称(private User user)
javaType:表示实体类属性的类型(User)(全限定名)
column:数据库返回结果集的字段名称
property:实体类属性名称
-->
<association property="user" javaType="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
</association>
</resultMap>
2)一对多
①User属性
public class User {
private int id;
private String username;
private String password;
private Date birthday;
//当前用户有哪些订单
private List<Order> orderList;
②UserMapper接口
public interface UserMapper {
List<User> findAll();
}
问题:
- 1)单单查询User表显示不了order表的信息,但发现order关联user的id。
- 2)mapper怎么手动指定;List集合属性的映射关系
解决:
铺垫:
先让order表和user表结合成1个表:内连接查询
SELECT * , o.id oid FROM orders o , USER u WHERE u.id = o.id
③UserMapper.xml
<mapper namespace="com.itheima.mapper.UserMapper">
<resultMap id="userMap" type="user">
//User的简单属性
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="birthday" property="birthday"/>
//User的Order集合属性
<!--配置集合:
property:User中集合的属性名称(List<Order> orderList)
ofType:集合的类型(Order)(全限定名:此处使用了自定义别名)
column:字段名称
-->
<collection property="orderList" ofType="order">
<!--封装Order数据-->
<id column="oid" property="id"/>
<result column="ordertime" property="orderTime"/>
<result column="total" property="total"/>
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select * ,o.id oid from user u ,orders o where u.id=o.uid
</select>
</mapper>
3)多对多
(将3个表进行内连接查询)
数据库:
select * from sys_user u,sys_user_role ur ,sys_role r where u.id = ur.userId and r.id = ur.roleId
①增加role实体类
public class Role {
private int id;
private String roleName;
private String roleDesc;
//省略set/get方法
}
②增加user实体类成员变量
public class User {
private int id;
private String username;
private String password;
private Date birthday;
private List<Order> orderList;//当前用户有哪些订单
//当前用户具备哪些角色
private List<Role> roleList;
③UserMapper接口
public interface UserMapper {
List<User> findUserAndRoleAll();
}
④UserMapper.xml
<mapper namespace="com.itheima.mapper.UserMapper">
<resultMap id="userRoleMap" type="user"> <!--type:封进哪里的全限定名-->
<!--User的简单属性-->
<id column="userId" property="id"/> <!--column:结果集字段-->
<result column="username" property="username"/>
<result column="password" property="password"/>
<!--User的roleList的Role集合属性-->
<collection property="roleList" ofType="role"> <!--ofType:集合类型(全限定名)-->
<id column="roleId" property="id"/>
<result column="roleName" property="roleName"/>
<result column="roleDesc" property="roleDesc"/>
</collection>
</resultMap>
<select id="findUserAndRoleAll" resultMap="userRoleMap">
select * from sys_user u ,sys_user_role ur,sys_role r where u.id = ur.userId and r.id = ur.roleId
</select>
</mapper>
二、注解开发方式
1)概述
2)简单de增删改查
①Mybatis核心文件配置
删除了mapper配置文件,接口和实体类是没有映射关系的,因为没有配置值文件Mybatis不知道谁跟谁有映射关系,不使用xml配置的话,记得要加载映射关系
【这里是扫接口的包】
<!--加载映射关系-->
<mappers>
<!--指定接口所在的包(扫包)-->
//<!--<mapper resource="com/itheima/mapper/AccountMapper.xml"></mapper>-->
<package name="com.itheima.mapper"/>
</mappers>
②UserMapper接口:声明注解
这里跟xml文件一样的,用方法的参数来赋SQL值
public interface UserMapper {
@Insert("insert into user values(#{id},#{username},#{password})")
void save(User user);
@Update("update user set username=#{username},password=#{password} where id=#{id}")
void update(User user);
@Delete("delete from user where id = #{id}")
void delete(int id);
@Select("select * from user where id = #{id}")
User findById(int id);
@Select("select * from user")
List<User> findAll();
}
③测试
public class Demo {
public User user = new User();
public UserMapper mapper;
@Before
public void before() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(UserMapper.class);
}
//增
@Test
public void testSave(){
user.setUsername("我是谁");
user.setPassword("123");
mapper.save(user);
}
//删
@Test
public void testDeleteById(){
mapper.delete(3);
}
//改
@Test
public void testUpdateById(){
user.setId(1);
user.setUsername("易烊");
user.setPassword("123");
mapper.update(user);
}
//查:1个
@Test
public void testFindAll(){
List<User> userList = mapper.findAll();
System.out.println(userList);
}
//查:所有
@Test
public void testFindById(){
User user = mapper.findById(1);
System.out.println(user);
}
}
3)实现复杂映射开发
1)一对一
0、实体类
public class User {
private int id;
private String username;
private String password;
//忽略get、set方法和toString
}
public class Order {
private int id;
private Date orderTime;//下单时间
private double total;//订单价格
private User user; //当前订单属于哪个客户
//忽略get、set方法和toString
①OrderMapper接口
public interface OrderMapper {
@Select("select * from user u,orders o where o.uid = u.id")
@Results({
//Order的简单属性
@Result(column = "id",property = "id"),//返回结果集的字段 与 Order属性值
@Result(column = "ordertime",property = "ordertime"),
@Result(column = "total",property = "total"),
//Order的User对象属性
@Result(column = "uid",property = "user.id"),//返回结果集的字段 与 Order中User对象的属性值
@Result(column = "username",property = "user.username"),
@Result(column = "password",property = "user.password")
})
List<Order> findAll();
}
②测试
public class Demo2 {
public User user = new User();
public OrderMapper mapper;
@Before
public void before() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
mapper = sqlSession.getMapper(OrderMapper.class);
}
@Test
public void test1(){
List<Order> orderList = mapper.findAll();
for (Order order : orderList) {
System.out.println(order);
}
}
对比一下xml:
2)一对多
2、一对一的第2种方式(常用)
第2种是什么方式呢?
上边的方式是使用
内连接
将2个表合成为1个表来查询
下面是通过1个表,1个表的查询
。
具体是 怎么样呢?
- 先查询orders表返回查询结果集
- 指定查询结果集中的uid(oders表中的外键,user表的主键), 根据uid查询user表
select * from useru,orders o where o.uid = u.id
↓分开
select * from orders (OrderMapper)
↓根据uid(复用)
select * from user where id = ? (UserMapper)
代码跟前面整个注解演示相关,这里只写出有改动的。
①UserMapper接口(上边已经定义<复用>)
根据id查询User:
@Select("select * from user where id = #{id}")
User findById(int id);
②OrderMapper接口
public interface OrderMapper {
@Select("select * from orders")
@Results({
//Order的简单属性
@Result(column = "id",property = "id"),//返回结果集的字段 与 Order属性值
@Result(column = "ordertime",property = "ordertime"),
@Result(column = "total",property = "total"),
//Order的User对象属性
@Result(
property = "user", //Order实体需要封装的属性名称
column = "uid", //根据orders返回查询结果集中的哪个字段进行查询
javaType = User.class, //Order中user属性名称的属性类型
//1对1
one = @One(select = "com.itheima.mapper.UserMapper.findById" ) //select属性:查询哪个接口的方法 获得 Order实体需要封装的属性
)
})//记得,这里是{ }是数组。
List<Order> findAll();
}
3)多对多
多对多:多对多都是有个中间表,这里也是将3个表的
内连接
,拆分成2个表来查询根据User的id 查询 某个User具备哪些角色:
select * from user u ,sys_user_role ur , sys_role r where ur.roleId = r.id and u.id = ?
↓ 拆分
select * from user
↓ 根据id查询
select * from sys_user_role ur ,sys_role r where ur.roleId = r.id and ur.userId = ?
①Role实体类
public class Role {
private int id;
private String roleName;
private String roleDesc;
②User实体类
public class User {
private int id;
private String username;
private String password;
//当前User具备多少个角色
private List<Role> roleList;
③RoleMapper接口
public interface RoleMapper {
@Select("select * from sys_user_role ur ,sys_role r where ur.roleId = r.id and ur.userId = #{uid}")
List<Role> findByUid(int uid);
}
④UserMapper接口
public interface UserMapper {
@Select("select * from user")
@Results({
//User的简单属性
@Result(column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
//User中Role集合属性
@Result(
property = "roleList", //封进哪个属性
column = "id", //根据哪个字段查询
javaType = List.class, //封进哪个属性的属性类型
//多对多
many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid") //调用某个方法查询
)
})
List<User> findUserAndRoleAll();
Mybatis+MySQL:插入记录,返回数据自动生成的id
这里还有1个属性keyColumn没设置,但是看下面解释应该能懂
useGeneratedKeys:必须设置为true,否则无法获取到主键id。
keyProperty:设置为POJO对象的主键id属性名称。
keyColumn:设置为数据库记录的主键id字段名称
mybatis中@Param的用法和作用
```java
@Select("select s_id id,s_name name,class_id classid from student where s_name= #{aaaa} and class_id = #{bbbb}")
public Student select(@Param("aaaa") String name,@Param("bbbb")int class_id);
当方法参数时1个时, 自定义命名可以直接映射,但是如果是多参数的话,即使每个参数的名称都是跟数据库字段名称一致,但是他还是分不清,所以要使用@Param注解来声明跟字段相匹配的名称。
(如果是对象的话,对象属性名称跟数据库名称相对应就可以映射。)