Mybatis是一个半自动化的ORM框架,是一个优秀的DAO层解决方案。
一 使用MyBatis的开发步骤
1.导入mybatis依赖
通过这个maven仓库去找依赖,https://mvnrepository.com/
三个依赖:mysql、mybatis、junit
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
<!-- junit测试包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
2.编写MyBatis核心配置文件
mybatis-config.xml,官网提供的名字。
在资源文件resources目录下,创建mybatis-config.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">
<!--mybatis的核心配置文件-->
<configuration>
<!--environments 数据库环境 1、开发环境 2、测试环境 3、生产环境-->
<environments default="dev">
<environment id="dev">
<!--事务管理 采用JDBC的事务管理机制-->
<transactionManager type="JDBC" />
<!--数据源配置信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/news_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--映射器-->
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
3.创建实体类-POJO、创建Dao层,编写接口文件
实体类
package cn.hxzy.pojo;
public class User {
private Integer userId;
private String userName;
private String userPwd;
private Integer userGender;
public User() {
}
public User(Integer userId, String userName, String userPwd, Integer userGender) {
this.userId = userId;
this.userName = userName;
this.userPwd = userPwd;
this.userGender = userGender;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public Integer getUserGender() {
return userGender;
}
public void setUserGender(Integer userGender) {
this.userGender = userGender;
}
}
定义接口文件的后缀名为Mapper,UserMapper.java。
package cn.hxzy.dao;
import cn.hxzy.pojo.User;
import java.util.List;
/**
* 用户的Mapper接口文件
*/
public interface UserMapper {
/**
* 查询全部用户信息
* @return 用户集合
*/
List<User> getUserList();
}
4.编写-SQL映射文件
在resources资源目录下,创建一个专门用于mapper文件的管理目录,在mapper文件夹下,创建与接口文件保持一致的SQL映射文件
UserMapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace-->
<mapper namespace="cn.hxzy.dao.UserMapper">
<select id="getUserList" resultType="cn.hxzy.pojo.User">
select * from user
</select>
</mapper>
maven的强大体现在有个特性叫做依赖传递。
5.创建工具类MybatisUtils.java
为了减少代码量,提高系统性能,把公共的操作封装在一起,方便代码的管理。
package cn.hxzy.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
//静态的属性,是属于类级别
public static SqlSessionFactory factory = null;
static { //只在类加载的时候,执行一次
String resource = "mybatis-config.xml"; //读取核心配置文件mybatis-config.xml
InputStream is = null;
try {
is = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
factory = new SqlSessionFactoryBuilder().build(is); //创建SqlSessionFactory对象
}
public static SqlSession creatSqlSession() {//创建creatSqlSession方法
return factory.openSession();
}
}
6.代码测试
package cn.hxzy.dao;
import cn.hxzy.pojo.User;
import cn.hxzy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserMapperTest1 {
@Test
public void getUserList() throws Exception{
SqlSession sqlSession = MybatisUtils.creatSqlSession(); //创建SqlSession对象
UserMapper userMapper =sqlSession.getMapper(UserMapper.class);//反射 调用mapper文件进行数据操作
List<User> userList = userMapper.getUserList();
for (User user:userList) {
System.out.println(user.getUserId()+"=="+user.getUserName());
}
sqlSession.close();
}
@Test
public void getUser(){
SqlSession sqlSession = MybatisUtils.creatSqlSession(); //创建SqlSession对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//调用mapper文件进行数据操作
User user = userMapper.getUser(12);
System.out.println(user.getUserId()+"==="+user.getUserName());
sqlSession.close();
}
}
二、 使用lombok的步骤
1.安装lombok插件
在File中找到Settings找到Pplugins,搜索Lombok,进行安装。
2.下载依赖
找到maven仓库,下载依赖,添加到pom.xml文件中
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
3.打开实体类,加入注解
@Data //get set
@AllArgsConstructor //有参构造方法
@NoArgsConstructor //无参构造方法
@ToString //重写toString方法
4.提取MybatisUtils工具类
为了减少代码量,提高系统性能,把公共的操作封装在一起,方便代码的管理。
package cn.hxzy.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
@author:mengshujun
@createTime: 2024-03-25 16:19:50 星期一
*/
public class MyBatisUtils {
//工厂对象
static SqlSessionFactory factory; //内存中只有一份拷贝...只有一个对象
static {
String path="mybatis-config.xml";
InputStream is = null;
try {
is = Resources.getResourceAsStream(path);
} catch (IOException e) {
e.printStackTrace();
}
factory = new SqlSessionFactoryBuilder().build(is);
}
public static SqlSession openSession(){
return factory.openSession(true);
}
}
三、参数入参
-
1、适用于单个参数的情况,默认按照类型入参,默认可以不写parameterType。
-
2、多个参数入参
这种情况需要添加@Param注解,进行参数名称的标注。xml文件节点上不可以添加parameterType。
-
3、可以封装为一个实体对象进行入参
对象加上@Param注解后,sql语句传入参数的表示方式为:#{student.studentId}
如果对象不加@Param注解,sql语句传入参数的表示方式为:#{studentId}
-
4、涉及到复杂数据类型传参的时候可以使用Map入参,可以加@Param("map")注解,如果添加上去后,sql语句就必须为#{map.studentId},如果没有添加
则可以直接使用map的键的名称入参
#{ }入参与${ }入参的区别:
1、#{ } 占位符,预编译的sql语句
2、${ },变量直接拼接到sql语句中,入参方式不安全。很容易被sql注入(利用sql语句,对系统进行攻击,破坏)
SELECT COUNT(1) FROM userinfo
WHERE user_name='aa' OR 1='1' AND user_pwd='bb' OR 1='1'
账号 aa' OR 1='1
密码 bb' OR 1='1
3、${ } 可以进行算术运算,#{ }不可以进行算术运算
四、事务提交
执行增删改操作的时候,默认的自动提交是关闭的,需要进行手动提交。
方式一:
sqlSession.commit();
方式二:
public static SqlSession creatSqlSession() {
return factory.openSession(true);
}
五、resultType与resultMap
返回类型别名设置:
<typeAliases>
<typeAlias alias="Grade" type="cn.hxzy.myschool"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>
或者
<typeAliases>
<package name="cn.hxzy.myschool.entity"/>
</typeAliases>
每一个在包 domain.blog
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。
resultMap:返回SQL语句映射的一个Map类型的结果集
数据库的经典命名法:
Orcal与Mysql
Orcal中一般字段名全部大写,如果遇到两个单词的情况,中间用下划线隔开。
mysql中一般字段名小写,如果遇到两个单词的情况,中间用下划线隔开。
resultType与resultMap不能同时存在于同一个语句块上。
六、高级结果映射
1. 映射方式
在实际生产环境中,对于这种多表联查,映射结果有以下几种处理办法。
1.1.做一个基于业务模块的DTO实体类,一般会把所用到的业务字段合为一个实体类进行操作
package cn.hxzy.dto;
import java.sql.Date;
public class NewsDto {
private Integer newsId;
private Integer newsTypeId;
private String newsTitle;
private String newsInfo;
private String newsFrom;
private String newsContent;
private Date createTime;
private String newsimg;
private String newsTypeTitle;
}
1.2.在实体类上修改字段
根据关系型数据表中,数据记录的关系,进行实体类属性的定义
2. 一对一的映射
实体类
package cn.hxzy.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.sql.Date;
/*
资讯实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class News {
private Integer newsId;
private NewsType newsType; //把此属性改为对象
private String newsTitle;
private String newsInfo;
private String newsFrom;
private String newsContent;
private Date createTime;
private String newsimg;
}
Mapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 命名空间..接口的包路径-->
<mapper namespace="cn.hxzy.dao.NewsMapper">
<!--对多表联查,自定义结果集-->
<resultMap id="newsList" type="News">
<id property="newsId" column="newsId" />
<result property="newsTitle" column="newsTitle" />
<result property="newsInfo" column="newsInfo" />
<result property="newsFrom" column="newsFrom" />
<result property="newsContent" column="newsContent" />
<result property="createTime" column="createTime" />
<result property="newsimg" column="newsimg" />
<!-- 指代的就是一个对象-->
<association property="newsType" javaType="NewsType">
<id property="newsTypeId" column="newsTypeId" />
<result property="newsTypeTitle" column="newsTypeTitle"/>
</association>
</resultMap>
<select id="selectAll" resultMap="newsList" >
SELECT * FROM news t1
LEFT OUTER JOIN newstype t2
ON t1.`newsTypeId`=t2.`newsTypeId`
</select>
</mapper>
接口
package cn.hxzy.dao;
import cn.hxzy.pojo.News;
import java.util.List;
public interface NewsMapper {
//查询全部的资讯信息
List<News> selectAll();
}
测试
package cn.hxzy.dao;
import cn.hxzy.pojo.News;
import cn.hxzy.pojo.User;
import cn.hxzy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class NewsMapperTest {
@Test
public void selectAll() throws Exception{
SqlSession sqlSession = MybatisUtils.creatSqlSession(); //对象
NewsMapper newsMapper = sqlSession.getMapper(NewsMapper.class);
List<News> newsList = newsMapper.selectAll();
for (News news:newsList) {
System.out.println(news.getNewsId()+"==="+news.getNewsTitle()+"==="+news.getNewsType().getNewsTypeTitle());
}
sqlSession.close();
}
}
3. 一对多的映射
实体类
package cn.hxzy.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.List;
/*
资讯类别表
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class NewsType {
private Integer newsTypeId;
private String newsTypeTitle;
/**
* 一对多
*/
private List<News> newsList; //资讯集合
}
Mapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 命名空间..接口的包路径-->
<mapper namespace="cn.hxzy.dao.NewsTypeMapper">
<resultMap id="userList" type="NewsType">
<id property="newsTypeId" column="newsTypeId"></id>
<result property="newsTypeTitle" column="newsTypeTitle"></result>
<!--collection表示的是集合属性 private List<News> newsList -->
<collection property="newsList" ofType="News">
<id property="newsId" column="newsId" />
<result property="newsTitle" column="newsTitle" />
<result property="newsInfo" column="newsInfo" />
<result property="newsFrom" column="newsFrom" />
<result property="newsContent" column="newsContent" />
<result property="createTime" column="createTime" />
<result property="newsimg" column="newsimg" />
</collection>
</resultMap>
<select id="getNewsByType" resultMap="userList">
SELECT * FROM newsType t1
LEFT JOIN news t2
ON t1.newsTypeId=t2.newsTypeId
</select>
</mapper>
接口
package cn.hxzy.dao;
import cn.hxzy.pojo.News;
import cn.hxzy.pojo.NewsType;
import java.util.List;
public interface NewsTypeMapper {
//根据资讯类别去查询所属的资讯信息
List<NewsType> getNewsByType();
}
测试
package cn.hxzy.dao;
import cn.hxzy.pojo.News;
import cn.hxzy.pojo.NewsType;
import cn.hxzy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class NewsTypeMapperTest {
@Test
public void getNewsByType() {
SqlSession sqlSession = MybatisUtils.creatSqlSession(); //对象
NewsTypeMapper newsTypeMapper = sqlSession.getMapper(NewsTypeMapper.class);
List<NewsType> newsTypeList = newsTypeMapper.getNewsByType();
for (NewsType newsType : newsTypeList) {
System.out.println(newsType.getNewsTypeId() + "===" + newsType.getNewsTypeTitle());
for (News news : newsType.getNewsList()) {
System.out.println(news.getNewsTitle());
}
}
sqlSession.close();
}
}
七、外部文件配置数据源
编写database.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ticket?serverTimezone=GMT%2B8&useUnicode=true&useSSL=false&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
说明:
serverTimezone=Asia/Shanghai"
或
serverTimezone=GMT%2B8
或
serverTimezone=UTC
核心配置文件中引入
<!--把数据库的连接信息配置在properties文件之下-->
<properties resource="database.properties"/>
更改数据源配置信息
<!--数据源配置信息-->
<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>
映射器(mappers)
1、使用相对于类路径的资源引用,默认会在resource资源目录下去找
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
2、使用完全限定资源定位符(URL)
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
3、使用映射器接口实现类的完全限定类名
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
4、将包内的映射器接口实现全部注册为映射器
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
setting设置项
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--映射方式默认的自动映射关闭-->
<setting name="autoMappingBehavior" value="PARTIAL"/>
<!--mybatis的日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/> <!--mybatis标准日志-->
</settings>
八、动态SQL
编写代码的时候,写的是基本结构,当程序运行的时候,会根据条件重新拼接SQL语句,从而生成新的SQL语句。
8.1 if....where语句块
<select id="selectBySearch" resultType="Train" parameterType="Train" >
SELECT * FROM train
<where>
<if test="train.startStation!=null or aa!=''">
and startStation=#{train.startStation}
</if>
<if test="train.startTime!=null">
and startTime=#{train.startTime}
</if>
</where>
</select>
mybatis使用LocalDateTime
把Date改造为LocalDateTime后,如果报红,则打开file-project structrue-modules 模块 language leave:提升一下语言版本最低为8以上
如果运行的时候,出现mysql报错信息,则升级Mysql8.0的依赖
注意:mybatis的版本必须为3.4.5+以上的版本,推荐使用3.5以上的版本。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
8.2 choose、when、otherwise
日期函数:
SELECT * FROM train_ticket
WHERE DATE_FORMAT(start_date,'%Y-%m-%d')='2022-06-22';
map入参,注意:map写在表达式中,
<select id="selectNewsListSearch" parameterType="java.util.Map" resultMap="newsList">
SELECT t1.*,t2.* FROM news t1
LEFT JOIN newstype t2
ON t1.`newsTypeId`=t2.`newstype_id`
<where>
<choose>
<when test="newsTypeId!=null">
and t2.newstype_id=#{map.newsTypeId}
</when>
<when test="newsTypeTitle!=null">
and t2.newstype_title=#{map.newsTypeTitle}
</when>
<otherwise>
and 1=1
</otherwise>
</choose>
</where>
</select>
模糊查询,使用concat函数拼接 % 百分号
AND news_title like concat("%",#{newsTitle},"%")
8.3 自定义 trim 元素
万能牌
<select id="selectBySearch" resultType="Train" parameterType="Train">
<trim prefix="where" prefixOverrides="AND | OR">
<if test="train.startStation!=null">
AND startStation=#{train.startStation}
</if>
<if test="train.startTime!=null">
and startTime=#{train.startTime}
</if>
</trim>
</select>
trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix;可以把包含内容的首部某些内容覆
盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOverrides;正因为trim有这样的功能,所以我们也可以非常简单的利用trim
来代替where元素的功能。
8.4 set语句
一般用于更新的情况
<update id="update">
UPDATE train_ticket
<set>
<if test="trainTicket.tripsName!=null">
trips_name=#{trainTicket.tripsName},
</if>
<if test="trainTicket.tripsTypeId!=0">
trips_type_id=#{trainTicket.tripsTypeId},
</if>
<if test="trainTicket.departureTerminal!=null">
departure_terminal=#{trainTicket.departureTerminal},
</if>
<if test="trainTicket.destination!=null">
destination=#{trainTicket.destination},
</if>
<if test="trainTicket.startDate!=null">
start_date=#{trainTicket.startDate},
</if>
<if test="trainTicket.endDate!=null">
end_date=#{trainTicket.endDate},
</if>
<if test="trainTicket.lasted!=0.0">
lasted=#{trainTicket.lasted},
</if>
</set>
where ticket_id=#{trainTicket.ticketId}
</update>
trim替换set示例:
<update id="updateNews">
UPDATE news
<trim prefix="set" suffixOverrides=",">
<if test="newsTitle!=null">
news_title=#{newsTitle},
</if>
<if test="categroy.categroyId!=0">
categroy_id=#{categroy.categroyId},
</if>
<if test="newsAuthor!=null">
news_author=#{newsAuthor},
</if>
<if test="createTime!=null">
create_time=#{createTime},
</if>
<if test="newsContent!=null">
news_content=#{newsContent},
</if>
</trim>
WHERE news_id=#{newsId}
</update>
8.5 foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
<delete id="delete" parameterType="java.util.List">
DELETE FROM train_ticket
WHERE ticket_id IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
注意:如果使用数组入参,则需要添加注解
int batchDelete(@Param("arr") int [] arr);
<foreach collection="arr" ...></foreach>
9、分页插件
9.1 在pom.xml添加依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
9.2 在Mybatis核心配置文件中设置分页插件
在setting之下添加插件配置
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
9.3 测试分页功能
/**limit index,pageSize
* index:当前页的起始索引
* pageSize:每页显示的条数
* pageNum:表示当前页的页码
* index=(pageNum-1)*pageSize
* @author:mengshujun
* @createTime: 2024-03-26 14:58:13 星期二
*/
@Test
public void test5(){
SqlSession sqlSession = MyBatisUtils.openSession();
NewsMapper newsMapper = sqlSession.getMapper(NewsMapper.class);
Page<News> pages = PageHelper.startPage(2, 5);
List<News> list = newsMapper.selectNewsList();
for (News news : list) {
System.out.println(news);
}
System.out.println("================");
int pageNum = pages.getPages();
System.out.println("总页数:"+pageNum);
long total = pages.getTotal();
System.out.println("总记录数:"+total);
int num = pages.getPageNum();
System.out.println("当前的页码:"+num);
}
十、注解开发
mybatis3.4.5这个版本后,引入了一种全新的开发模式,这个模式脱离了xml的映射文件,使用主键的方式把sql语句进行集中的标注,使开发变得更加简洁。
10.1 单表操作
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
然后在Mapper接口的方法上,加上特定的注解实现对数据库表的操作
例如:
@Select("select * from user")
List<User> findAllTest();
@Select("select * from user where id = #{id}")
User findByIdTest(int id);
@Insert("insert into user values(#{id},#{username},#{password},#{birthday});")
int saveTest(User user);
@Delete("delete from user where id = #{id};")
int deleteTest(@Param("id") int id);
@Update("update user set username=#{username},password=#{password} where id = #{id};")
int updateTest(User user);
在新增操作中,往往有一种需求,要得到上一次插入数据的主键值,可以使用@Options注解
@Insert("INSERT INTO news (news_title,categroy_id,news_author) VALUES(#{newsTitle},#{categroyId},#{newsAuthor})")
@Options(useGeneratedKeys=true,keyProperty="newsId")
int insertNews(NewsSaveDto newsSaveDto);
设置maven的默认编译器使用的jdk版本1.5,升级为1.8
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.resource>1.8</maven.compiler.resource>
</properties>
10.2 动态SQL
@Update({"<script>",
"update news ",
" <set>",
" <if test='news.newsId!=0'>newsId=#{news.newsId},</if>",
" <if test='news.newsTitle!=null'>newsTitle=#{news.newsTitle},</if>",
" </set>",
"<where>",
"newsId=#{news.newsId}",
"</where>",
"</script>"}
)
int updateNews(@Param("news") News news);
十一、注解实现复杂映射开发
@Results:可以与@Result 一起使用,封装多个结果集,代替<resultMap>
@Result:实现结果集封装
-
column:数据库的列名
-
property:需要装配的属性名
-
one:需要使用的@One 注解(@Result(one=@One)()))
-
many:需要使用的@Many 注解(@Result(many=@many)()))
@One:实现一对一结果集封装,代替<assocation>
使用格式:@Result(column=" ",property="",one=@One(select=""))
@Many:实现一对多结果集封装,代替<collection>
使用格式:@Result(property="",column="",many=@Many(select=""))
实体类:
News实体类
package cn.hxzy.news.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class News implements Serializable {
private int newsId;
private String newsTitle;
private String newsInfo;
private String newsFrom;
private String newsContent;
private Date createTime;
private String newsimg;
private NewsType newsType; //自定义的类型使用的时候,需要创建对象(赋值是看业务)(一对一)
}
NewsType实体类
package cn.hxzy.news.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NewsType implements Serializable {
private int newsTypeId;
private String newsTypeTitle;
//一对多
private List<News> newsList;
public NewsType(String newsTypeTitle) {
this.newsTypeTitle = newsTypeTitle;
}
public NewsType(int newsTypeId, String newsTypeTitle) {
this.newsTypeId = newsTypeId;
this.newsTypeTitle = newsTypeTitle;
}
}
11.1 一对一查询
当查询一个表,需要把另一个表的数据也同时查询出来时
NewsMapper接口
public interface NewsMapper {
@Select("select * from news")
@Results({
@Result(id = true, column = "newsId", property = "newsId"),
@Result(column = "newsTitle", property = "newsTitle"),
@Result(column = "newsInfo", property = "newsInfo"),
@Result(column = "newsFrom", property = "newsFrom"),
@Result(column = "newsContent", property = "newsContent"),
@Result(column = "createTime", property = "createTime"),
@Result(column = "newsimg", property = "newsimg"),
@Result(column = "newsTypeId",property = "newsType",
javaType = NewsType.class, one = @One(select = "cn.hxzy.news.mapper.NewsTypeMapper.selectNewsType"))
})
List<News> selectNewsList();
}
NewsTypeMapper接口
package cn.hxzy.news.mapper;
import cn.hxzy.news.entity.NewsType;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface NewsTypeMapper {
@Select("select * from newsType where newstype_id=#{newsTypeId}")
@Results({
@Result(id = true,column = "newstype_id",property = "newsTypeId"),
@Result(column = "newstype_title",property = "newsTypeTitle")
})
NewsType selectNewsType(@Param("newsTypeId") int newsTypeId);
}
2.2 一对多查询
1.查询单个类别对应多个资讯的情况
NewsMapper
public interface NewsMapper {
@Select("select * from news where newsTypeId=#{newsTypeId}")
List<News> selectNewsListByTypeId(int newsTypeId);
}
NewsTypeMapper
public interface NewsTypeMapper {
@Select("select * from newsType where newstype_id=#{newsTypeId}")
@Results({
@Result(id = true,column = "newstype_id",property = "newsTypeId"),
@Result(column = "newstype_title",property = "newsTypeTitle"),
@Result(column = "newstype_id",property = "newsList",javaType = List.class,
many = @Many(select = "cn.hxzy.news.mapper.NewsMapper.selectNewsListByTypeId"))
})
NewsType selectNewsType(@Param("newsTypeId") int newsTypeId);
}
2.查询多个类别对应多个资讯的情况
NewsMapper
public interface NewsMapper {
@Select("select * from news where newsTypeId=#{newsTypeId}")
List<News> selectNewsListByTypeId(int newsTypeId);
}
NewsTypeMapper
@Select("select * from newsType")
@Results({
@Result(id = true,column = "newstype_id",property = "newsTypeId"),
@Result(column = "newstype_title",property = "newsTypeTitle"),
@Result(column = "newstype_id",property = "newsList",javaType = List.class,
many = @Many(select = "cn.hxzy.news.mapper.NewsMapper.selectNewsListByTypeId"))
})
List<NewsType> selectNewsTypeList();
十二、SQL语句块
<sql id="columns">
t1.newsId,
t1.`newsTypeId`,
t1.`newsTitle`,
t1.`newsInfo`,
t1.`newsFrom`,
t1.`newsContent`,
t1.`createTime`,
t1.`newsimg`,
t2.`newstype_id`,
t2.`newstype_title`
</sql>
<sql id="newsSearch">
SELECT
<include refid="columns"/>
FROM news t1
LEFT JOIN newstype t2 ON t1.`newsTypeId`=t2.`newstype_id`
</sql>
<select id="selectNewsListSearch" parameterType="java.util.Map" resultMap="newsList">
<include refid="newsSearch"/>
<where>
<choose>
<when test="newsTypeId!=null">
and t2.newstype_id=#{newsTypeId}
</when>
<when test="newsTypeTitle!=null">
and t2.newstype_title=#{newsTypeTitle}
</when>
<otherwise>
and 1=1
</otherwise>
</choose>
</where>
</select>
十三、mybatis缓存
缓存:内存中的一块特定的空间
1、减轻数据库的访问压力
2、提升了查询的效率
缓存是只针对查询业务有效,增删改操作会更新缓存。
13.1 一级缓存
作用范围在一个sqlsession之间,如果中间有增删改操作会更新缓存,或者手动关闭sqlSession,一级缓存默认是开启的
13.2 二级缓存
二级缓存可以进行数据共享,在线程中可以进行数据共享。
<mapper namespace="com.mybatis.cache.mapper.NewsMapper">
<!-- 声明这个namespace使用二级缓存 -->
<!-- (1)<cache/> -->
<!-- (2)也可以自定义缓存配置属性,开启二级缓存二选一即可 -->
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"
size="1024"
eviction="FIFO"
flushInterval="120000"
readOnly="false"/>
</mapper>
属性 | 含义 | 取值 |
---|---|---|
type | 缓存实现类 | 需要实现Cache接口,默认是PerpetualCache,可以使用第三方缓存 |
size | 最多缓存对象个数 | 默认1024 |
eviction | 回收策略(缓存淘汰算法) | LUR - 最近最少使用;移除最长时间不被使用的对象(默认) FIFO - 先进先出;按对象进入缓存的顺序来移除它们. SOFT - 软引用: 移除基于垃圾回收器状态和软引用规则的对象. WEAK - 弱引用:更积极的移除基于垃圾收集器状态和弱引用规则的对象 |
flushInterval | 定时自动清空缓存间隔 | 自动刷新时间,单位ms,未配置时只有调用时的刷新 |
readOnly | 是否只读 | true: 只读缓存:会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供来很重要的性能优势。 false: 读写缓存:会返回缓存对象的拷贝(通过序列化),不会共享。这会慢一些,但是安全,因此默认是false 改为false可读写时,对象必须支持序列化. |
注解开发在接口类上添加:@CacheNamespace可以开启二级缓存
web高并发,依赖,辅助。
redis第三方 redis搭建集群
微服务