MyBatis框架
这里写的感觉有点多,到时候拆开发,需要哪看目录就好🤗
ORM(对象关系映射)
ORM即对象关系映射(Object-Relationl Mapping),它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。
配置环境和文件
1.mybatis所需jar
必须:
<mybatis.version>3.2.8</mybatis.version>
<slf4j.version>1.7.12</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<druid.version>1.0.9</druid.version>
<!-- mybatis框架包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
非必需:
<!-- log -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- lombok(这个后面会说) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
2.创建主配置文件mybatis-config.xml相关配置
注:可以点击
configuration
标签来查看写入标签的顺序,参数标签可以不写但是顺序不能倒置
<configuration>
<!--引入properties文件-->
<properties resource="jdbc.properties"></properties>
<settings>
<!-- 配置打印SQL语句
value="STDOUT_LOGGING"(在控制台打印sql) value="LOG4J"(将打印的sql放置到log4j日志文件中)-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--
设置Mybatis的自动映射模式
FULL:全自动映射(可映射复杂数据类型,但是影响性能)
NONE:关闭自动映射,全手动映射
PARTIAL:默认半自动映射
-->
<!-- <setting name="autoMappingBehavior" value="FULL"/>-->
</settings>
<!-- 简化包名(起个别名) -->
<typeAliases>
<package name="com.r.pojo"/>
</typeAliases>
<!-- 创建数据源 默认加载rr,可以有多个数据源 -->
<environments default="rr">
<environment id="rr">
<!-- 事务的加载类型:比如jdbc -->
<transactionManager type="JDBC"></transactionManager>
<!--连接信息-->
<!--
dataSource—数据源,type属性、其有三种取值:
"POOLED":使用连接池
"JNDI":和tomcat关联性比较大,不推荐
"UNPOOLED":不使用连接池
-->
<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>
<!-- 扫描mapper文件,不要忘记添新的!!! -->
<mappers>
<mapper resource="mapper/ProviderDao.xml"/>
<mapper resource="mapper/UserVoMapper.xml"/>
</mappers>
</configuration>
3. 编写测试类
String resource = "mybatis-config.xml";
try {
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
/**
* true 自动提交事务 (默认)
* false 关闭自动提交
* 不写可能会导致增加、更新和删除的成功但数据库没有改的现象
*/
SqlSession sqlSession = factory.openSession(true);
UserVoDao userVoDao = sqlSession.getMapper(UserVoDao.class);
userVoDao.getUserId(10);
//关闭sqlsession
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
SQL映射的XML文件
SQL映射文件的几个元素(按照定义的顺序)
- mapper – namespace
- cache – 配置给定命名空间的缓存
- cache-ref – 从其他命名空间引用缓存配置
- resultMap –用来描述数据库结果集和对象的对应关系
- sql – 可以重用的SQL块,也可以被其他语句引用
- insert – 映射插入语句
- update – 映射更新语句
- delete – 映射删除语句
- select – 映射查询语句
SQL映射文件
文件形式一般为:~mapper.xml
或是~dao.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="命名空间(全路径)">
<!--方法名与ID必须一致-->
<!--parameterType 传入参数类型-->
<!--resultType 返回值类型-->
<select id="接口方法名"
resultType="返回值类型"
parameterType="参数类型" >
这里是写sql语句的地方
</select>
</mapper>
SQL映射文件参数传递
文件形式一般为:~mapper.java
或是~dao.java
接口层
单参数
接口中定义:
public Provider findProviderById(Long id);
映射文件中代码:
<select id="findProviderById"
resultType="Provider"
parameterType="long" >
select * from jntm_provider where id = #{id}
</select>
多个参数
使用注解@Param (作用:起个别名)
(如果别名类型是对象的话那映射文件中sql就用 别名.属性
)
接口中定义:
public int updateProviderInfo(@Param("name") String proName, @Param("id") Long id);
映射文件中代码:
<!-- 注意:parameterType为对象名 -->
<update id="updateProviderInfo" parameterType="Provider">
update jntm_provider set proName = #{name} where id = #{id}
</update>
使用map集合
可用于多条件查询,或多个对象传回一个对象的类型
接口中定义:
public List<User> findUserInfo(Map<String, Object> map);
映射文件中代码:
<select id="findUserInfo"
resultType="User">
<!-- 用map来传值的时候#{}里面的值为map的key -->
<!--
#与$区别:
#:是占位符
$:是原样输出
所以可以有下面的两种写法,但$不推荐
-->
select * from jntm_user
where userName like concat ('%', #{name}, '%') and
address like '%${address}%' and
gender = #{sex}
</select>
测试类:
@Test
public void findUserInfo() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
Map<String, Object> map = new HashMap<>();
map.put("name", "Hank");
map.put("sex", 1);
map.put("address", "温馨的小窝");
List<User> users = userDao.findUserInfo(map);
System.out.println(users.size());
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}
SQL映射文件获取关系值
一对一
对象套对象:association
实体类:
添上一行
//一对一
private Role role;
然后getter()、setter()
映射文件代码:
<!-- 手动映射 -->
<resultMap id="userResult" type="User">
<id property="id" column="id"/>
<result property="userName" column="name"/>
<!-- 一对一映射:
property是上面实体类属性名
javaType是被映射的实体类名
-->
<association property="role" javaType="Role">
<result property="roleName" column="roleName"/>
</association>
</resultMap>
<select id="findUserById" resultType="User" resultMap="userResult">
select a.id,a.userCode,a.userName as name,a.userPassword,b.roleName from jntm_user a
left join jntm_role b on a.userRole = b.id
where a.id = #{id}
</select>
一对多
对象套集合:collection
实体类:
添上一行
//一对多
private List<Address> addressList;
然后getter()、setter()
映射文件代码:
<!-- 手动映射 -->
<resultMap id="userResultAddress" type="User">
<id property="id" column="id"/>
<result property="userName" column="userName"/>
<!-- 一对多映射:
property是上面实体类属性名
ofType是被映射的实体类名(注意和一对一的不一样嗷~)
-->
<collection property="addressList" ofType="Address">
<result property="contact" column="contact"/>
<result property="addressDesc" column="addressDesc"/>
</collection>
</resultMap>
<select id="findUserAddress" resultType="User" resultMap="userResultAddress">
SELECT a.id,a.userName,b.contact,b.addressDesc FROM jntm_user a
LEFT JOIN jntm_address b ON a.id = b.userId
WHERE a.id = #{id}
</select>
全自动映射的情况
映射文件可以这样写:
<resultMap id="userResult" type="User">
<id property="id" column="id"/>
<result property="userName" column="name"/>
<!-- 一对一映射:
property是上面实体类属性名
javaType是被映射的实体类名
-->
<association property="role" javaType="Role">
<!-- 是的这里什么都没有 -->
</association>
</resultMap>
<select id="findUserById" resultType="User" resultMap="userResult">
select a.id,a.userCode,a.userName as name,a.userPassword,b.roleName from jntm_user a
left join jntm_role b on a.userRole = b.id
where a.id = #{id}
</select>
这样就能映射上,但是不推荐全自动映射,因为把所有的都自动映射上了,性能会降低
简化实体类的插件工具:Lombok
使用方法
Maven导入(上面如果导了的话这个就不用了)
pom.xml:
<!-- 导入lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
然后来到你的实体类,加个注解,这样就可以不用getter()和setter()了:
@Data //比如这样
public class UserVo {
//我是属性
}
@Data
:什么都有,比如getter()、setter()、toString()、RequiredArgsConstructor()等等…
@Getter
:单纯的getter()
@Setter
:有单纯的getter()就也有单纯的setter()咯~
@ToString
:重写toString方法
@NoArgsConstructor
:无参构造方法
@AllArgsConstructor
:所有有参构造方法
@NonNull
:添加空指针检查…
还有一堆,简单知道一下就够用了😬
MyBatis测试工具类
MyBatisUtil.java
package com.r.util;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private static SqlSessionFactory factory;
static{
//在静态代码块下,factory只会被创建一次
System.out.println("static factory===============");
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SqlSession createSqlSession(){
return factory.openSession(true);//true 为自动提交事务
}
public static void closeSqlSession(SqlSession sqlSession){
if(null != sqlSession)
sqlSession.close();
}
}
测试类使用时,方法就两个:
SqlSession sqlSession = MyBatisUtil.createSqlSession(); //创建
ProviderDao providerDao = sqlSession.getMapper(ProviderDao.class); //DAO层接口实现
//int n = providerDao.updateProviderInfo("xxx公司",25L); //写的具体方法
//System.out.println("受影响行数:" + n);
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
tips:用这个可以方便很多重复代码,下面的示例测试类中都用了这个
动态SQL
if + where(查询)
<select id="findUserList" resultType="User">
select * from jntm_user
<where>
<if test="uName != null">
userName like concat ('%', #{uName} ,'%')
</if>
<if test="beginBirthday != null">
and birthday > #{beginBirthday}
</if>
<if test="endBirthday !=null">
and birthday < #{endBirthday}
</if>
</where>
order by birthday desc limit #{pyl},#{pageSize}
</select>
<where>
标签会自动不要第一个and,如果<if>
标签里面都为null,那么就相当于
<where>
里面什么都没有嗷~
</where>
来实现动态sql的目的
- 注:
>
:大于号>
<
:小于号<
if + trim(都可以,但不推荐,一般用于insert)
<insert id="insertUserInfo">
insert into jntm_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userCode != null">userCode,</if>
<if test="userName != null">userName,</if>
<if test="userPassword != null">userPassword,</if>
<if test="gender != null">gender,</if>
<if test="birthday != null">birthday,</if>
<if test="phone != null">phone,</if>
<if test="role != null">userRole,</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userCode != null">#{userCode},</if>
<if test="userName != null">#{userName},</if>
<if test="userPassword != null">#{userPassword},</if>
<if test="gender != null">#{gender},</if>
<if test="birthday != null">#{birthday},</if>
<if test="phone != null">#{phone},</if>
<if test="role != null">#{role.id},</if>
</trim>
</insert>
prefix
: 给sql语句拼接的前缀suffix
: 给sql语句拼接的后缀prefixOverrides
:去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"suffixOverrides
:去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定
if + set(修改)
<update id="updateUserInfo">
update jntm_user
<set>
<if test="userCode != null">userCode = #{userCode},</if>
<if test="userName != null">userName = #{userName},</if>
<if test="userPassword != null">userPassword = #{userPassword},</if>
<if test="phone != null">phone = #{phone}</if>
</set>
where id = #{id}
</update>
foreach(遍历)
三种情况:
List集合入参
dao层接口
/**
* 根据多个角色id查找用户集合
* list集合入参
* @param roleids
* @return
*/
public List<User> findUserLists(List<Integer> roleids);
映射文件:
<select id="findUserLists" resultType="User">
select * from jntm_user where userRole in
<foreach item="ids" collection="list" open="(" separator="," close=")">
#{ids}
</foreach>
</select>
- 单参数时,
collection
这里要写类型:
list
:集合array
:数组map-key
(写自己map的key名)- 多参数时,写接口中设置的相应(集合/数组)参数名或map中key名
item
:自己设一个用于遍历的值名就行
open
:前缀
separator
: 中间以什么隔开
close
:后缀
测试类:
@Test
public void findUserLists() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
List<User> userList = userDao.findUserLists(list);
for (User user : userList) {
System.out.println(user.toString());
}
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}
数组入参
dao层接口
/**
* 根据多个角色id和性别查找用户
* 数组入参
* @param roleids
* @return
*/
public List<User> findUserArrays(@Param("roleids") Integer[] roleids,
@Param("gender") Integer gender);
映射文件:
<select id="findUserArrays" resultType="User">
select * from jntm_user where userRole in
<foreach item="ids" collection="roleids" open="(" separator="," close=")">
#{ids}
</foreach>
and gender = #{gender}
</select>
与上面解释一样,因为是多参数,所以此处
collection
中没有写array
而是写了接口的参数名
测试类:
@Test
public void findUserArrays() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.findUserArrays(new Integer[]{1, 2}, 1);
for (User user : userList) {
System.out.println(user.toString());
}
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}
Map入参
dao层接口
/**
* 根据多个角色id和性别查找用户
* Map入参
* @param map
* @return
*/
public List<User> findUserMaps(Map<String, Object> map);
映射文件:
<select id="findUserMaps" resultType="User">
select * from jntm_user where userRole in
<foreach item="ids" collection="roleids" open="(" separator="," close=")">
#{ids}
</foreach>
and gender = #{gender}
</select>
这里的
collection
和#{gender}
均为下面测试类中map对象的key名,要对应好
测试类:
@Test
public void findUserMaps() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
Map<String, Object> map = new HashMap<>();
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
map.put("roleids", list);
map.put("gender", 1);
List<User> userList = userDao.findUserMaps(map);
for (User user : userList) {
System.out.println(user.toString());
}
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}
choose(when otherwise)
相当于if-elseif,和JSTL中的语法差不多
test
里面不止可以写=
、也可以>
、<
<when>
相当于elseif
<otherwise>
相当于else
<!-- 语法 -->
<choose>
<when test ="条件1"> …</when>
<when test ="条件2"> …</when>
<when test ="条件3"> …</when>
…
<otherwise>…</otherwise>
</choose>
用到的情况比较少,就写了一个不太和逻辑的小例子,但是意思是那么个意思
dao层接口
/**
* 只修改用户其中一个字段的信息
* @param user
* @return
*/
public int updateUserInfo1(User user);
映射文件:
<!-- 哪个不为空就改哪个,多个不为空则只改sql语句靠前的第一个条件 -->
<update id="updateUserInfo1">
update smbms_user
<set>
<choose>
<when test="userCode != null">userCode = #{userCode},</when>
<when test="userName != null">userName = #{userName},</when>
<when test="userPassword != null">userPassword = #{userPassword},</when>
<when test="phone != null">phone = #{phone}</when>
<otherwise><!-- 这里什么也没写(因不符合当前小例子情况),如果什么都不写会返回所有,如果是查询语句数据量非常大的情况而这里不写的话,就是一个深渊巨坑哈哈哈 --></otherwise>
</choose>
</set>
where id = #{id}
</update>
测试类:
@Test
public void updateUserInfo1() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = new User();
//哪个不为空就改哪个,多个不为空则只改sql语句靠前的第一个条件
user.setUserCode("2222"); //也就是如果先改了这一行,则下行就不会执行了,只改了一行
user.setUserName("Rose的Hank");
user.setId(17);
int n = userDao.updateUserInfo1(user);
System.out.println("受影响行数:" + n);
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}
sql片段
当映射文件sql语句中存在一些重复代码时来使用,说白了就是代码复用,也方便了不少
<!-- 语法 -->
<!-- 建立sql片段 -->
<sql id="Tuerlechat">
......
</sql>
SELECT * FROM XXX
<trim prefix="where" prefixOverrides="and ">
<!-- 调用sql片段, 标签include -->
<include refid="Tuerlechat"/>
</trim>
tips:建立sql片段中的
id
和调用sql片段中的refid
要一致嗷~
多条件查询翻页和记录总条数的小示例
因为翻页和记录总条数中的一些条件代码都一致,所以就用这个写个小示例😎
dao层接口
/**
* 多条件查询加翻页
* @param uName
* @param beginBirthday
* @param endBirthday
* 上面的参数是查询的条件,下面这两个是用来翻页的
* @param pyl
* @param pageSize
* @return
*/
public List<User> findUserList(
@Param("uName") String uName,
@Param("beginBirthday") String beginBirthday,
@Param("endBirthday") String endBirthday,
@Param("pyl") Integer pyl,
@Param("pageSize") Integer pageSize);
/**
* 查询总记录数
* @return
*/
public int findUserListCount(
@Param("uName") String uName,
@Param("beginBirthday") String beginBirthday,
@Param("endBirthday") String endBirthday);
映射文件:
<!-- 这里是sql片段 -->
<sql id="sql_where">
<where>
<if test="uName != null">
userName like concat ('%', #{uName} ,'%')
</if>
<if test="beginBirthday != null">
and birthday > #{beginBirthday}
</if>
<if test="endBirthday !=null">
and birthday < #{endBirthday}
</if>
</where>
</sql>
<!-- 这里是sql语句 -->
<select id="findUserList" resultType="User">
select * from jntm_user
<include refid="sql_where"></include>
order by birthday desc limit #{pyl},#{pageSize}
</select>
<select id="findUserListCount" resultType="Integer">
select count(1) from jntm_user
<include refid="sql_where"></include>
</select>
这样就都是可以共用的😎
Mybatis通过注解实现动态sql和手动映射
注解实现普通sql
@Select
/**
* 根据id查用户
* @param id
* @return
*/
//这里直接正常这么写就行
@Select("select * from jntm_user where id = #{id}")
public User findUserById1(Integer id);
@Insert
@Insert("insert into jntm_user (userCode,userName) values ("222","kuma")")
public User insertUserInfo();
@Update
@Update("update jntm_user set userName = #{name} where id = #{id}")
public int updateUserInfo(@Param("name") String userName,
@Param("id") Integer id);
@Delete
@Delete("delete from jntm_user where id = #{id}")
public User deleteUserById(Integer id);
注解实现动态sql
两种方式实现:
1、在注解里面写<script>
脚本
dao层接口
/**
* 根据是否传id返回相应用户信息(可能集合可能单个对象)
* 使用注解查询动态sql(第一种方式)
* @param map
* @return
*/
@Select("<script> " +
"select * from smbms_user" +
"<where>" +
"<if test = \" id != null and id != '' \"> " +
"id = #{id} " +
"</if>" +
"</where>" +
"</script>")
List<User> findUserByCondition(Map<String, Object> map);
测试类:
@Test
public void findUserByCondition() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
Map<String, Object> map = new HashMap<>();
//map.put("id", 17); 看看效果
List<User> userList = userDao.findUserByCondition(map);
for (User user : userList) {
System.out.println(user.toString());
}
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}
2、使用@SelectProvider注解
dao层接口
/**
* 根据相应条件返回集合或单个对象
* 使用注解查询动态sql(第二种方式)
* @param user
* @return
*/
@SelectProvider(type = UserXXX.class, method = "findUserByCondition1")
List<User> findUserByCondition1(User user);
type
:是用来写动态sql的类
method
:是上面那个类中的sql对应实现方法
UserXXX.java
/**
*
* @Author Tuerlechat,
* @Date 2022/10/27
*/
public class UserXXX {
//使用@SelectProvider注解
@SelectProvider
//这里是方法名
public String findUserByCondition1(User user) {
//返回个SQL(){}.toString();
return new SQL() {
{
//开始写sql...
SELECT(" * ");
FROM("jntm_user").WHERE("1 = 1");
if ((user.getUserCode()) != null) {
WHERE("userCode like concat ('%', #{userCode}, '%')");
}
if ((user.getUserName()) != null) {
WHERE("userName like '%${userName}%'");
}
}
}.toString();
}
}
测试类:
@Test
public void findUserByCondition1() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = new User();
user.setUserCode("2");
user.setUserName("朴");
List<User> userList = userDao.findUserByCondition1(user);
for (User u : userList) {
System.out.println(u.toString());
}
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}
注解实现手动映射
两种方式实现:
1、一体的写:直接在注解里设置映射
sql语句是连表的,映射的属性property对应的对象写到具体属性一级来一一对应,和正常的语句流程感觉还是差不多的
/**
* 根据id查询用户信息和角色名
* 一对一
* @param id
* @return
*/
@Results(id = "userResult1", value = {
@Result(id = true, property = "id", column = "uid"),
@Result(property = "userName", column = "userName"),
@Result(property = "role.id", column = "rid"),
@Result(property = "role.roleName", column = "roleName")
})
@Select("select u.id uid,u.userName,r.id rid,r.roleName from jntm_user u,jntm_role r where u.userRole = r.id and u.id = #{id}")
public User findUserById11(Integer id);
2、分着写:用注解@One和@Many
这个写起来刚开始会有一点点不适应,找了一堆资料也都没有说的很明白的,只能自己摸索,踩了个大坑😑
使用时注意事项:
虽然只是用到了dao层接口,用不到映射文件,但是映射文件也必须创建!!!没错是必须,写个命名空间然后空着就行,导致运行一直报错,搞的脑子都混了🤮
语法:
@Insert("sql语句") //插入
@Update("sql语句") //更新
@Delete("sql语句") //删除
@Select("sql语句") //查询
//映射集
@Results({
@Result(id = true, property = "", column = ""),
@Result(property = "", column = ""),
//省略一些映射字段。。。
//需要一对一(或一对多和多对多)的字段
@Result(property = "", //要封装的属性名称
column = "", //根据当前表中的哪个字段来去查询目标表的数据(就是相关联的那一部分(外键))
javaType = , //要封装的实体类型
one = @One(select = "") //全限定名的要引用的另一个dao接口的方法
//一对多是这个,和上面的@One用法一样
//many = @Many(select = "")
)
})
- @One:一对一结果集封装
- @Many:一对多结果集封装
示例
一对一
还是上面那个例子,不过写法不同
根据id查询用户信息和角色名
User实体类:
@Data
public class User {
//此处省略一些字段。。。
//一对一
private Role role; //返回类型是对象
}
UserDao:
/**
* 根据id查询用户信息和角色名
* 一对一结果集封装 @one
* @param id
* @return
*/
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "userCode", column = "userCode"),
@Result(property = "userName", column = "userName"),
@Result(property = "role", //要封装的实体属性名
column = "userRole", //根据哪个字段去查询目标表的数据
javaType = Role.class, //要封装的的目标方法返回值类型
one = @One(select = "com.r.dao.RoleDao.findRoleById")
)
})
@Select("select * from jntm_user where id=#{id}")
public User findUserById11(Integer id);
RoleDao:
/**
* 根据id查询角色信息
* @param id
* @return
*/
@Select("select * from jntm_role where id = #{id}")
public Role findRoleById(Integer id);
一对多
根据id查询用户多个地址
User实体类:
@Data
public class User {
//此处省略一些字段。。。
//一对多
private List<Address> addressList;
}
UserDao:
/**
* 根据id查询用户多个地址
* 一对多
* @param id
* @return
*/
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "userCode", column = "userCode"),
@Result(property = "userName", column = "userName"),
@Result(property = "addressList", //要封装的实体属性名
column = "id", //根据哪个字段去查询目标表的数据
javaType = List.class, //要封装的目标方法返回值类型
many = @Many(select = "com.r.dao.AddressDao.findAddress") //@many
)
})
@Select("select * from jntm_user where id = #{id}")
public User findUserAddress11(Integer id);
AddressDao:
/**
* 查询地址信息
* @return
*/
@Select("select * from jntm_address")
//如果是全表都可以一对多映射的话则打开此映射集,因为这个例子里User返回的是单个对象,而Address返回的是List集合,开启此映射集会互相映射,会报错,若使用应将两个方法都改成一致的返回值类型,像本例这样不使用但也可以单方面映射自己需要的信息
// @Results({
// @Result( property = "contact", column = "contact"),
// @Result(property = "addressDesc", column = "addressDesc"),
// @Result(property = "user",
// column = "userId",
// javaType = User.class,
// one = @One(select = "com.r.dao.UserDao.findUserAddress11") //@One
// )
// })
public List<Address> findAddress();
多对多
一个User有多个Role,一个Role也有多个User
tips:练习库没有类似情况,所以只是写个示例
User实体类:
@Data
public class User {
//此处省略一些字段。。。
//多对多
private List<Role> roleList;
}
Role实体类(如果是一体写RoleDao则不需要设置,但分着写需要映射):
@Data
public class Role {
//此处省略一些字段。。。
//多对多
private List<Role> roleList;
}
UserDao:
/**
* 根据id查询用户信息和角色名
* 多对多结果集封装 @Many
* @return
*/
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "userCode", column = "userCode"),
@Result(property = "userName", column = "userName"),
@Result(property = "address", column = "address"),
@Result(property = "roleList", //要封装的属性名称
column = "userRole", //根据哪个字段去查询目标表的数据
javaType = List.class, //要封装的实体类型
many = @Many(select = "com.r.dao.RoleDao.findRoleById1")
)
})
@Select("select * from jntm_user")
public List<User> findUserById111();
RoleDao:
/**
* 根据id查询角色信息
* @return
*/
// 一体写法 @Select("select * from jntm_role a, smbms_user b where a.id = b.userRole and a.id = #{id}")
//分着写,记得加实体类
@Results({
@Result(property = "roleName", column = "roleName"),
@Result(property = "userList", //要封装的属性名称
column = "id", //根据哪个字段去查询目标表的数据
javaType = List.class, //要封装的实体类型
many = @Many(select = "com.r.dao.UserDao.findUserById111")
)
})
@Select("select * from jntm_role where id = #{id}")
public List<Role> findRoleById1(Integer id);
测试类:
@Test
public void findUserById111() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.findUserById111();
for (User user : userList) {
System.out.println(user.toString());
}
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}
其它:@One、@Many注解同时写一起
刚才的多对多例子,因为剩了一个一对一的属性,就试了试😂
UserDao:
/**
* 根据id查询用户信息和角色名
* 多对多结果集封装 @Many
* @return
*/
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "userCode", column = "userCode"),
@Result(property = "userName", column = "userName"),
@Result(property = "address", column = "address"),
@Result(property = "role", //要封装的属性名称
column = "userRole", //根据哪个字段去查询目标表的数据
javaType = Role.class, //要封装的实体类型
one = @One(select = "com.r.dao.RoleDao.findRoleById")
),
@Result(property = "roleList", //要封装的属性名称
column = "userRole", //根据哪个字段去查询目标表的数据
javaType = List.class, //要封装的实体类型
many = @Many(select = "com.r.dao.RoleDao.findRoleById1")
)
})
@Select("select * from jntm_user")
public List<User> findUserById111();
测试类:
@Test
public void findUserById111() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.findUserById111();
for (User user : userList) {
System.out.println(user.getId()+"---"+user.getUserName());
System.out.println("用户角色名称:" + user.getRole().getRoleName());
}
MyBatisUtil.closeSqlSession(sqlSession); //释放资源
}