网站建设前端学什么语言,响应式网站建站,做电子请帖的网站,网站页面统计代码是什么意思文章目录 Mybatis概述什么是Mybatis#xff1f;Mybatis导入知识补充数据持久化持久层 第一个Mybatis程序#xff1a;数据的增删改查查创建环境编写代码1、目录结构2、核心配置文件#xff1a;resources/mybatis-config.xml3、mybatis工具类#xff1a;Utils/MybatisUtils4、… 文章目录 Mybatis概述什么是MybatisMybatis导入知识补充数据持久化持久层 第一个Mybatis程序数据的增删改查查创建环境编写代码1、目录结构2、核心配置文件resources/mybatis-config.xml3、mybatis工具类Utils/MybatisUtils4、PojoUser5、Dao接口UserDao6、Mapper配置文件UserMapper.xml 测试常见问题汇总 第一个Mybatis程序完善优化后的整体目录结构1、通过db.properties文件配置数据库连接的基本设置2、配置多套环境3、起别名4、映射器 mappers 第一个Mybatis程序进阶resultMap问题描述解决1改变Sql语句在sql中起别名解决2使用resultMap注意事项 模糊查询日志日志工厂STDOUT_LOGGING使用LOG4J使用 分页Limit分页RowBounds分页分页插件PageHelper 注解开发实现实现关于 Param(“”) 注解#{} 和 ${} 的区别 Lombok 第二个Mybatis程序基础多对一处理案例背景编写代码1、Pojo2、Utils3、Dao按照查询嵌套处理4、Dao按照结果嵌套处理5、结果 总结association 第二个Mybatis程序进阶一对多处理案例背景编写代码1、Pojo2、Utils3、Dao按照查询嵌套处理4、Dao按照结果嵌套处理5、结果 总结collection 动态SQL什么是动态SQL环境搭建动态SQL-IF动态SQL-choose、when、otherwise动态SQL-Set动态SQL-trim、sql片段动态SQL-foreach 缓存简介Mybatis缓存一级缓存二级缓存Mybatis调用顺序 自定义缓存-ehcache介绍 Mybatis概述
什么是Mybatis
MyBatis 是一款优秀的持久层框架它支持自定义 SQL、存储过程以及高级映射MyBatis 免除了几乎所有的 JDBC代码以及设置参数和获取结果集MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJOPlain Old Java Objects普通老式 Java 对象为数据库中的记录
Mybatis导入 Maven仓库https://mvnrepository.com/artifact/org.mybatis/mybatis 官方文档中文https://mybatis.org/mybatis-3/zh/index.html
知识补充
数据持久化
持久化就是将程序的数据从瞬时状态转化为持久状态的过程 生活结合冰箱冷藏 内存中的数据断电即失可以持久化存储数据的媒介数据库jdbc、io文件
持久层
完成持久化工作的代码块Dao层Service层Controller层…
第一个Mybatis程序数据的增删改查查
创建环境
1、Maven项目创建
2、新建一个模块
3、导入相关依赖
4、建立数据库环境
-- 建表
CREATE TABLE user(
id INT(20) NOT NULL PRIMARY KEY,
name VARCHAR(30) DEFAULT NULL,
pwd VARCHAR(30) DEFAULT NULL
)ENGINEINNODB DEFAULT CHARSETutf8;-- 插入语句
INSERT INTO user(id, name, pwd) VALUES
(1, 狂神, 123456),
(2, 张三, 1234567),
(3, 李四, 1234568)编写代码
1、目录结构 后续按代码编写顺序贴出相关代码 2、核心配置文件resources/mybatis-config.xml 主要完成对数据库的配置连接和Dao层xml文件的注册 ?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd!--核心配置文件--
configurationenvironments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver valuecom.mysql.cj.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/learn_mybatis?useSSLfalseamp;useUnicodetrueamp;characterEncodingUTF-8/property nameusername valueroot/property namepassword value123456//dataSource/environment/environments!-- 每一个Mapper.xml都需要在MyBatis核心配置文件中注册--mappersmapper resourceGSF/Example/Dao/UserMapper.xml//mappers/configurationmappers标签下的内容是在写了Dao层代码后写入的
3、mybatis工具类Utils/MybatisUtils 每次连接数据库之前都需要通过sqlSessionFactory来获取sqlSession对象从而进行后续的数据库连接、sql执行、关闭操作 将该获取过程提取抽象写为工具类方便每次调用使用 package GSF.Example.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 {private static SqlSessionFactory sqlSessionFactory;static {String resources mybatis-config.xml;InputStream inputStream null;try {inputStream Resources.getResourceAsStream(resources);sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {throw new RuntimeException(e);}}public static SqlSession getSqlsession(){return sqlSessionFactory.openSession();}
}4、PojoUser 和数据库中数据表相对应的实体类对象 字段和数据表字段基本一一对应如果不对应也可以通过一个resultMap映射完成不对应字段之间的关联 set、get方法很关键是执行sql语句完毕后将查询结果写入实体类对象的关键 package GSF.Example.Pojo;public class User {private int id;private String name;private String pwd;public User(){}public User(int id, String name, String pwd) {this.id id;this.name name;this.pwd pwd;}public int getId() {return id;}public void setId(int id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd pwd;}Overridepublic String toString() {return User{ id id , name name \ , pwd pwd \ };}
}5、Dao接口UserDao 定义获取数据库对象的接口方法 package GSF.Example.Dao;import GSF.Example.Pojo.User;import java.util.List;
import java.util.Map;public interface UserDao {ListUser getUserList();// 根据id查询用户User getUserById(int id);//插入一个用户int addUser(User user);// 用map的方式插入用户int addUserByMap(MapString, Object map);//修改用户int updateUser(User user);//删除一个用户int deleteUser(int id);
}6、Mapper配置文件UserMapper.xml 写入接口方法的具体实现需要写入相应的sql语句 代替的是原来UserDaoImpl中的相关实现写完此配置文件需要向 “2” 的核心配置文件中注册该mapper
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
!-- namespace绑定一个Dao/Mapper接口--
mapper namespaceGSF.Example.Dao.UserDao!-- select查询语句ID对应方法名--select idgetUserList resultTypeGSF.Example.Pojo.Userselect * from learn_mybatis.user/selectselect idgetUserById parameterTypeint resultTypeGSF.Example.Pojo.Userselect * from learn_mybatis.user where id#{id}/selectinsert idaddUser parameterTypeGSF.Example.Pojo.Userinsert into learn_mybatis.user(id, name, pwd) values (#{id}, #{name}, #{pwd});/insertinsert idaddUserByMap parameterTypemapinsert into learn_mybatis.user(id, name, pwd) values (#{user_id}, #{user_name}, #{user_pwd});/insertupdate idupdateUser parameterTypeGSF.Example.Pojo.Userupdate learn_mybatis.user set name#{name}, pwd#{pwd} where id#{id};/updatedelete iddeleteUser parameterTypeintdelete from learn_mybatis.user where id#{id};/delete
/mapper测试
1、测试UserTest
package GSF.Example.Dao;import GSF.Example.Pojo.User;
import GSF.Example.Utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.HashMap;
import java.util.List;public class UserTest {Testpublic void GetUserList(){// 官方建议用try...catch包裹可以不用SqlSession sqlsession MybatisUtils.getSqlsession();try {UserDao mapper sqlsession.getMapper(UserDao.class);ListUser userList mapper.getUserList();for (User user : userList) {System.out.println(user);}}catch (Exception e){e.printStackTrace();}finally {sqlsession.close();}}Testpublic void GetUserById(){SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);User user mapper.getUserById(2);System.out.println(user);sqlsession.close();}Testpublic void AddUser(){SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);// 插入成功返回值为1int flag mapper.addUser(new User(10, GSF, qwerty));System.out.println(flag);sqlsession.commit();sqlsession.close();}Testpublic void AddUserByMap(){SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);// 插入成功返回值为1HashMapString, Object map_obj new HashMap();map_obj.put(user_id, 12);map_obj.put(user_name, 121212);map_obj.put(user_pwd, zxcxvz);int flag mapper.addUserByMap(map_obj);System.out.println(flag);sqlsession.commit();sqlsession.close();}Testpublic void UpdateUser(){SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);int flag mapper.updateUser(new User(1, 123, 12345678));System.out.println(flag);sqlsession.commit();sqlsession.close();}Testpublic void DeleteUser(){SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);int flag mapper.deleteUser(1);System.out.println(flag);sqlsession.commit();sqlsession.close();}
}常见问题汇总
第一次写程序可能遇到各种各样错误基本都涵盖如下
Dao层Mapper.xml配置文件没有在mybatis-config.xml中注册maven导出资源问题【资源不放在resources文件夹下正常情况下没法输出到target文件夹中】 通过配置资源导出的目录解决该问题
!-- 在项目的pom.xml文件中加入此配置 --buildresourcesresourcedirectorysrc/main/resources/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includes/resourceresourcedirectorysrc/main/java/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includes/resource/resources
/buildsrc/main/resources和src/main/java目录下的所有.xml文件和.properties文件都会被识别为资源从而在构建的时候输出到target目录
第一个Mybatis程序完善
优化后的整体目录结构 1、通过db.properties文件配置数据库连接的基本设置
db.properties
drivercom.mysql.cj.jdbc.Driver
urljdbc:mysql://localhost:3306/learn_mybatis?useUnicodetruecharacterEncodingutf-8
usernameroot
password123456url中不需要转义符了 原url内容jdbc:mysql://localhost:3306/learn_mybatis?useSSLfalseamp;useUnicodetrueamp;characterEncodingUTF-8
mybatis-config.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd!--核心配置文件--
configuration!-- properties标签的位置有严格的限制不能随意位置更改--properties resourcedb.properties/environments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver value${driver}/property nameurl value${url}/property nameusername value${username}/property namepassword value${password}//dataSource/environment/environments
/configuration删除其他配置方便理解当前改动
2、配置多套环境
mybatis-config.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd!-- 核心配置文件 --
configuration
!-- properties标签的位置有严格的限制不能随意位置更改 --properties resourcedb.properties/!-- 通过更改default的值来实现不同环境的切换 --environments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver value${driver}/property nameurl value${url}/property nameusername value${username}/property namepassword value${password}//dataSource/environmentenvironment idtesttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver valuecom.mysql.cj.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/learn_mybatis?useSSLfalseamp;useUnicodetrueamp;characterEncodingUTF-8/property nameusername valueroot/property namepassword value123456//dataSource/environment/environments
/configuration3、起别名
mybatis-config.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd!--核心配置文件--
configuration!--properties标签的位置有严格的限制不能随意位置更改--properties resourcedb.properties/typeAliases!-- 给特定类名起别名给出类的全路径标识给出别名--typeAlias typeGSF.Example.Pojo.User aliasUser/!--导入包名在类名上没有注解的情况下包内所有类的别名默认为类名的首字母小写--package nameGSF.Example.Pojo//typeAliasesenvironments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver value${driver}/property nameurl value${url}/property nameusername value${username}/property namepassword value${password}//dataSource/environment/environments
/configuration4、映射器 mappers
方式1将xml文件注册进核心配置文件mybatis-config.xml【强烈推荐】
不需要注意xml配置文件和对应的Dao层java代码的名字是否一致
mappersmapper resourceGSF/Example/Dao/UserDao.xml/
/mappers方式2将接口类的完全限定名注册进核心配置文件mybatis-config.xml
mappersmapper classGSF.Example.Dao.UserDao/
/mappers需要保证接口和其mapper配置文件同名需要保证接口和其mapper配置文件在同一个文件夹下 方式3将包注册进核心配置文件mybatis-config.xml
mapperspackage nameGSF.Example.Dao/
/mappers需要保证的内容跟方法2一样
第一个Mybatis程序进阶
resultMap 解决pojo实体类中对应属性名和数据库中对应字段名不一致的问题 问题描述
当数据库的字段和实体类的字段不一致的时候进行访问会出现不一致的字段为空
数据库字段 实体类字段 获取id1的数据库数据 解决1改变Sql语句在sql中起别名
select idgetUserById parameterTypeint resultTypeGSF.Example.Pojo.Userselect id,name,pwd as password from mybatis.user where id #{id}
/select解决2使用resultMap
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd!-- namespace绑定一个Dao/Mapper接口--
mapper namespaceGSF.Example.Dao.UserDaoresultMap idUserMap typeGSF.Example.Pojo.User!-- column数据库中的列名property实体类中的属性名一样的就无需再配置进来配置了也不影响--result columnpwd propertypassword//resultMap!--select查询语句ID对应方法名--select idgetUserList resultMapUserMapselect id, name, pwd from learn_mybatis.user/selectselect idgetUserById parameterTypeint resultTypeuserselect id, name, pwd as password from learn_mybatis.user where id#{id}/select
/mapperresultMap标签下的result标签定义不一致字段之间的对应关系对应的select标签需要将resultType改为resultMap
注意事项
当实体类没有空参构造即使有字段不一致Mybatis会强制将实体类中的字段和数据库中的字段进行属性匹配 可能出现字段不一致但是并没有 字段null 的情况出现
模糊查询
等到了项目理解的才能更深刻
现在暂时参考如下文章https://blog.csdn.net/Adobe_java/article/details/118460709
日志
日志工厂 有代码出问题了日志就是最好的排错手段 mybatis官方支持的7种实现日志的方式 掌握LOG4J第三方jar包、STDOUT_LOGGING标准日志输出
STDOUT_LOGGING使用
mybatis-config.xml配置即可
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd!--核心配置文件--
configuration!-- properties标签的位置有严格的限制不能随意位置更改 --properties resourcedb.properties/!-- settings标签依旧有严格的位置限制 --settings!-- name和value的一个字都不能和官方规定的不一致不要字符不一致不要有多余的空格 --setting namelogImpl valueSTDOUT_LOGGING//settingsenvironments defaultdevelopment....../environments/configuration设置了日志后的控制台输出 LOG4J使用
什么是log4j
Log4j是Apache的一个开源项目通过使用Log4j我们可以控制日志信息输送的目的地是控制台、文件、GUI组件我们也可以控制每一条日志的输出格式通过定义每一条日志信息的级别我们能够更加细致地控制日志的生成过程通过一个配置文件来灵活地进行配置而不需要修改应用代码
log4j使用
1、导包
Mavenhttps://mvnrepository.com/artifact/log4j/log4j
2、log4j.properties配置固定名字【放在resources文件夹下】
### 配置根 ###
log4j.rootLogger debug,console,file### 配置输出到控制台 ###
log4j.appender.console org.apache.log4j.ConsoleAppender
log4j.appender.console.Target System.out
log4j.appender.console.Threshold debug
log4j.appender.console.layout org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern %d{ABSOLUTE} %5p %c{1}:%L - %m%n### 配置输出到文件 ###
log4j.appender.file org.apache.log4j.FileAppender
log4j.appender.file.File ./log/GSF.loglog4j.appender.file.Append true
log4j.appender.file.Threshold debuglog4j.appender.file.layout org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n### 配置输出到文件并且每天都创建一个文件 ###
log4j.appender.dailyRollingFile org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyRollingFile.File logs/log.log
log4j.appender.dailyRollingFile.Append true
log4j.appender.dailyRollingFile.Threshold debug
log4j.appender.dailyRollingFile.layout org.apache.log4j.PatternLayout
log4j.appender.dailyRollingFile.layout.ConversionPattern %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n### 设置输出sql的级别其中logger后面的内容全部为jar包中所包含的包名 ###
log4j.logger.org.mybatisdebug
log4j.logger.java.sqldebug
log4j.logger.java.sql.Connectiondebug
log4j.logger.java.sql.Statementdebug
log4j.logger.java.sql.PreparedStatementdebug
log4j.logger.java.sql.ResultSetdebug3、mybatis-config.xml配置
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd!--核心配置文件--
configuration!-- properties标签的位置有严格的限制不能随意位置更改--properties resourcedb.properties/settingssetting namelogImpl valueLOG4J//settingsenvironments defaultdevelopment....../environments/configuration前三个步骤完成后访问数据库相关操作就可以记录到日志中
4、代码中手动设置日志输出
package GSF.Example.Dao;import GSF.Example.Pojo.User;
import GSF.Example.Utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;import java.util.HashMap;
import java.util.List;public class UserTest {static Logger logger Logger.getLogger(UserTest.class);Testpublic void GetUserList(){logger.info(info级别的日志基本信息该种日志打印出来表示系统的正常运行痕迹);logger.debug(debug级别的日志用于排查错误内容该种日志打印出来用于排除系统的错误);logger.error(error级别的日志用于输出错误信息该种日志打印出来往往是异常捕捉后的输出);SqlSession sqlsession MybatisUtils.getSqlsession();try {UserDao mapper sqlsession.getMapper(UserDao.class);ListUser userList mapper.getUserList();for (User user : userList) {System.out.println(user);}}catch (Exception e){e.printStackTrace();}finally {sqlsession.close();}}
}类中导入包定义对象 因为日志中可以记录当前日志在什么文件中写入所以logger的定义需要绑定当前类的class文件每个使用log4j的方法都需要在其类中定义logger对象自认为待确认
分页
Limit分页
SELECT * FROM user limit startIndex,pageSize;
SELECT * FROM user limit 0,2;
SELECT * FROM user limit 3; #[0,3]1、接口定义
//分页
ListUser getUserByLimit(MapString,Integer map);2、mapper.xml配置
!-- 分页--
select idgetUserByLimit parameterTypemap resultMapUserMapselect * from mybatis.user limit #{startIndex},#{pageSize}
/select3、测试
Test
public void getUserByLimit(){SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);HashMapString, Integer map new HashMap();map.put(startIndex,1);map.put(pageSize,2);ListUser userList mapper.getUserByLimit(map);for (User user : userList) {System.out.println(user);}sqlSession.close();RowBounds分页 不建议使用 1、接口定义
//分页2
ListUser getUserByRowBounds();2、mapper.xml配置
!--分页2--
select idgetUserByRowBounds resultMapUserMapselect * from mybatis.user
/select3、测试
Test
public void getUserByRowBounds(){SqlSession sqlSession MybatisUtils.getSqlSession();//RowBounds实现RowBounds rowBounds new RowBounds(1, 2);//通过java代码层面实现分页ListUser userList sqlSession.selectList(com.qjd.dao.UserMapper.getUserByRowBounds,null,rowBounds);for (User user : userList) {System.out.println(user);}sqlSession.close();
}分页插件PageHelper
官方地址https://pagehelper.github.io/docs/howtouse/
注解开发实现 本质基于反射和动态代理实现 实现
1、接口上写入注解
package GSF.Example.Dao;import GSF.Example.Pojo.User;
import org.apache.ibatis.annotations.*;import java.util.List;
import java.util.Map;public interface UserMapper {Select(select * from learn_mybatis.user)ListUser getUserList();//方法存在多个参数所有的参数前面前面必须加上 Param() 注解Select(select * from learn_mybatis.user where id#{id})User getUserByID(Param(id) int id);Insert(insert into learn_mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd}))int addUser(User user);Insert(insert into learn_mybatis.user(id,name,pwd) values(#{user_id},#{user_name},#{user_pwd}))int addUserByMap(MapString, Object map);Update(update learn_mybatis.user set name#{name},pwd#{password} where id#{id})int updateUser(User user);Delete(delete from learn_mybatis.user where id#{uid})int deleteUser(Param(uid) int id);
}2、mybatis-config.xml核心配置文件的配置
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd!--核心配置文件--
configuration......!-- 注册--mappersmapper classGSF.Example.Dao.UserMapper//mappers/configuration3、测试
package GSF.Example.Dao;import GSF.Example.Pojo.User;
import GSF.Example.Utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.HashMap;
import java.util.List;public class UserTest {Testpublic void GetUserList() {// 官方建议用try...catch包裹可以不用SqlSession sqlsession MybatisUtils.getSqlsession();try {UserMapper mapper sqlsession.getMapper(UserMapper.class);ListUser userList mapper.getUserList();for (User user : userList) {System.out.println(user);}} catch (Exception e) {e.printStackTrace();} finally {sqlsession.close();}}Testpublic void GetUserById() {SqlSession sqlsession MybatisUtils.getSqlsession();UserMapper mapper sqlsession.getMapper(UserMapper.class);User user mapper.getUserByID(2);System.out.println(user);sqlsession.close();}Testpublic void AddUser() {SqlSession sqlsession MybatisUtils.getSqlsession();UserMapper mapper sqlsession.getMapper(UserMapper.class);// 插入成功返回值为1int flag mapper.addUser(new User(20, GSF, qwerty));System.out.println(flag);sqlsession.commit();sqlsession.close();}Testpublic void AddUserByMap() {SqlSession sqlsession MybatisUtils.getSqlsession();UserMapper mapper sqlsession.getMapper(UserMapper.class);// 插入成功返回值为1HashMapString, Object map_obj new HashMap();map_obj.put(user_id, 21);map_obj.put(user_name, 121212);map_obj.put(user_pwd, zxcxvz);int flag mapper.addUserByMap(map_obj);System.out.println(flag);sqlsession.commit();sqlsession.close();}Testpublic void UpdateUser() {SqlSession sqlsession MybatisUtils.getSqlsession();UserMapper mapper sqlsession.getMapper(UserMapper.class);int flag mapper.updateUser(new User(1, 123, 12345678));System.out.println(flag);sqlsession.commit();sqlsession.close();}Testpublic void DeleteUser() {SqlSession sqlsession MybatisUtils.getSqlsession();UserMapper mapper sqlsession.getMapper(UserMapper.class);int flag mapper.deleteUser(1);System.out.println(flag);sqlsession.commit();sqlsession.close();}}关于 Param(“”) 注解
基本类型的参数或者String需要加上 如果只有一个基本类型的话可以忽略但是建议加上 引用类型的参数不需要加该注解比如User、Map…在sql中引用的就是Param(“”)注解中设定的属性名
#{} 和 ${} 的区别
#{}${}预编译处理是字符串替换处理#{}时会将sql中的#{}整体替换为占位符即?调用PreparedStatement的set方法来赋值在处理 $ { } 时就是把 ${ } 替换成变量的值可有效防止SQL注入无法防止SQL注入
预编译的机制
预编译是提前对SQL语句进行预编译而后再调用SQL注入的参数就不会再进行SQL编译而SQL注入是发生在编译的过程中因为恶意注入了某些特殊字符最后被编译为SQL时轻而易举的通过从而导致数据泄露预编译机制则可以很好的防止SQL注入
Lombok Lombok项目是一个Java库他是一个插件它会自动插入编辑器和构建工具中Lombok提供了一组有用的注释用来消除Java类中的大量样板代码。仅五个字符Data就可以替换数百行代码从而产生干净简洁且易于维护的Java类 使用步骤
在IDEA中安装Lombok插件在项目中导入Lombok的jar包在实体类上加入注解
Data
AllArgsConstructor
NoArgsConstructor
public class User {private int id;private String name;private String password;
}注解含义Data提供属性的set、get方法、无参构造AllArgsConstructor提供类的全参构造NoArgsConstructor提供类的无参构造
第二个Mybatis程序基础多对一处理
案例背景
描述
多个学生对应一个老师对于学生而言多个学生关联一个老师【多对一】对于老师而言一个老师集合对应多个学生【一对多】
要求
查询所有的学生及其关联的老师信息
数据库创建
-- 新建老师表
CREATE TABLE teacher (id INT(10) NOT NULL,name VARCHAR(30) DEFAULT NULL,PRIMARY KEY (id)
) ENGINEINNODB DEFAULT CHARSETutf8-- 插入老师数据
INSERT INTO teacher(id, name) VALUES (1, 秦老师);-- 新建学生表
CREATE TABLE student (id INT(10) NOT NULL,name VARCHAR(30) DEFAULT NULL,tid INT(10) DEFAULT NULL,PRIMARY KEY (id),KEY fktid (tid),CONSTRAINT fktid FOREIGN KEY (tid) REFERENCES teacher (id)
) ENGINEINNODB DEFAULT CHARSETutf8-- 插入学生数据
INSERT INTO student (id, name, tid) VALUES
(1, 小明, 1),
(2, 小红, 1),
(3, 小张, 1),
(4, 小李, 1),
(5, 小王, 1)编写代码
1、Pojo
老师类
import lombok.Data;Data
public class Teacher {private int id;private String name;
}学生类
import lombok.Data;Data
public class Student {private int id;private String name;//学生需要关联一个老师private Teacher teacher;
}2、Utils
写法参照《第一个Mybatis程序数据的增删改查查》
3、Dao按照查询嵌套处理
思路子查询
查询所有的学生信息根据查询出来的学生的tid寻找对应的老师
Mapper.xml
select idgetTeacher resultTypeGSF.Example.Pojo.Teacherselect * from learn_mybatis.teacher where id#{id}
/select!--根据查询嵌套处理--
select idgetStudent resultMapgetStudentselect id, name, tid from learn_mybatis.student;
/selectresultMap idgetStudent typeGSF.Example.Pojo.Studentresult propertyid columnid/result propertyname columnname/association propertyteacher columntid javaTypeGSF.Example.Pojo.Teacher selectgetTeacher/
/resultMaptest.java
Test
public void GetStudent() {// 官方建议用try...catch包裹可以不用SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);ListStudent students mapper.getStudent();for (Student student : students) {System.out.println(student);}sqlsession.close();
}4、Dao按照结果嵌套处理
思路子查询
查询所有的学生信息、老师信息将结果嵌套处理
Mapper.xml
select idgetStudent2 resultMapgetStudent2select s.id s_id ,s.name s_name, t.id t_id, t.name t_name from learn_mybatis.student s, learn_mybatis.teacher twhere s.tidt.id
/selectresultMap idgetStudent2 typeGSF.Example.Pojo.Studentresult propertyid columns_id/result propertyname columns_name/association propertyteacher javaTypeGSF.Example.Pojo.Teacherresult propertyid columnt_id/result propertyname columnt_name//association
/resultMaptest.java
Test
public void GetStudent() {// 官方建议用try...catch包裹可以不用SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);ListStudent students mapper.getStudent();for (Student student : students) {System.out.println(student);}sqlsession.close();
}5、结果
Student(id1, name小明, teacherTeacher(id1, name秦老师))
Student(id2, name小红, teacherTeacher(id1, name秦老师))
Student(id3, name小张, teacherTeacher(id1, name秦老师))
Student(id4, name小李, teacherTeacher(id1, name秦老师))
Student(id5, name小王, teacherTeacher(id1, name秦老师))总结association
association标签处理关联关系即多对一 标签属性含义javaType集合对象的类型
第二个Mybatis程序进阶一对多处理
案例背景
描述
多个学生对应一个老师对于学生而言多个学生关联一个老师【多对一】对于老师而言一个老师集合对应多个学生【一对多】
要求
查询对应id的老师信息及其包含的所有学生
数据库创建
同上
编写代码
1、Pojo
老师类
package GSF.Example.Pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;NoArgsConstructor
AllArgsConstructor
Data
public class Teacher {private int id;private String name;private ListStudent students;
}学生类
package GSF.Example.Pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;NoArgsConstructor
AllArgsConstructor
Data
public class Student {private int id;private String name;private int tid;
}2、Utils
写法参照《第一个Mybatis程序数据的增删改查查》
3、Dao按照查询嵌套处理
思路子查询
查询对应id的老师信息根据查询出来的老师的tid寻找对应的学生
Mapper.xml
select idgetTeacher2 resultMapTeacherStudent2select * from learn_mybatis.teacher where id#{id}
/select
resultMap idTeacherStudent2 typeGSF.Example.Pojo.Teacher!--两个地方用到id这个result就得写出来不然不展示老师的id--result propertyid columnid/result propertyname columnname/collection propertystudents columnid javaTypeArrayList ofTypeGSF.Example.Pojo.Student selectgetStudentByTeacherId/
/resultMapselect idgetStudentByTeacherId resultTypeGSF.Example.Pojo.Studentselect * from learn_mybatis.student where tid #{id}
/selecttest.java
Test
public void GetTeacherById2() {// 官方建议用try...catch包裹可以不用SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);Teacher teacher mapper.getTeacher2(1);System.out.println(teacher);sqlsession.close();
}4、Dao按照结果嵌套处理
思路子查询
查询对应id的所有老师、学生信息将结果嵌套处理
Mapper.xml
select idgetTeacher resultMapgetTeacherselect s.id s_id, s.name s_name, t.name t_name, t.id t_idfrom learn_mybatis.student s, learn_mybatis.teacher twhere s.tid t.id and t.id#{id}
/selectresultMap idgetTeacher typeGSF.Example.Pojo.Teacherresult propertyid columnt_id/result propertyname columnt_name/collection propertystudents javaTypeArrayList ofTypeGSF.Example.Pojo.Studentresult propertyid columns_id/result propertyname columns_name/result propertytid columnt_id//collection
/resultMaptest.java
Test
public void GetTeacherById() {// 官方建议用try...catch包裹可以不用SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);Teacher teacher mapper.getTeacher(1);System.out.println(teacher);sqlsession.close();
}5、结果
Teacher(id1, name秦老师, students[Student(id1, name小明, tid1), Student(id2, name小红, tid1), Student(id3, name小张, tid1), Student(id4, name小李, tid1), Student(id5, name小王, tid1)])总结collection collection标签处理集合关系即一对多 标签属性含义javaType集合对象的类型ofType集合对象的类型
动态SQL
什么是动态SQL
简单来说就是根据不同的判断条件和需要来动态拼接SQL语句。
在Mybatis之前动态SQL的描述需要耗费很大精力。借助强大的OGNL表达式Mybatis3替换了之前的大部分元素使得动态SQL的描述变得简单很多。
环境搭建
数据库环境
--
CREATE TABLE blog(
id VARCHAR(50) NOT NULL COMMENT 博客id,
title VARCHAR(100) NOT NULL COMMENT 博客标题,
author VARCHAR(30) NOT NULL COMMENT 博客作者,
create_time DATETIME NOT NULL COMMENT 创建时间,
views INT(30) NOT NULL COMMENT 浏览量
)ENGINEINNODB DEFAULT CHARSETutf8INSERT INTO blog(id,title,author,create_time,views) VALUES
(1, 如何学Python, 青, 2022-10-11, 300),
(2, 如何学Java, 刘, 2022-10-12, 400),
(3, 如何学Django, 郭, 2022-10-13, 700)java项目环境及相关配置参考前文 Dao实体类
Data
public class Blog {private int id;private String title;private String author;private Date createTime;private int views;
}动态SQL-IF
public interface UserDao {ListBlog getBlogIf(MapString, Object map);
}select idgetBlogIf parameterTypemap resultTypeGSF.Example.Pojo.Blogselect * from learn_mybatis.blog where 11if testtitle ! nulland title#{title}/ifif testauthor ! nulland author#{author}/if
/select-- 若传入空的map真实的sql语句
select * from learn_mybatis.blog where 11-- 若传入的map带有title键真实的sql语句
select * from learn_mybatis.blog where 11 and title?-- 若传入的map带有title键和author键真实的sql语句
select * from learn_mybatis.blog where 11 and title? and author?IF标签不具备自动添加and的功能每个拼接的子SQL语句需要自行添加and
Test
public void GetBlogIf() {SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);MapString, Object objectMap new HashMap();//注释掉就返回默认检索的所有情况objectMap.put(title, 如何学Django);objectMap.put(author, 刘);ListBlog blogIf mapper.getBlogIf(objectMap);for (Blog blog : blogIf) {System.out.println(blog);}sqlsession.close();
}动态SQL-choose、when、otherwise
public interface UserDao {ListBlog getBlogChoose_When_Otherwise(MapString, Object map);
}select idgetBlogChoose_When_Otherwise parameterTypemap resultTypeGSF.Example.Pojo.Blogselect * from learn_mybatis.blog!-- 这里用到了下一个查询才讲述的where标签 --wherechoosewhen testtitle ! nulland title #{title}/whenwhen testauthor !nulland author #{author}/whenotherwiseand id 1/otherwise/choose/where
/select-- 若传入空的map真实的sql语句
select * from learn_mybatis.blog where id1-- 若传入的map带有title键真实的sql语句
select * from learn_mybatis.blog where title?-- 若传入的map带有title键和author键真实的sql语句
select * from learn_mybatis.blog where title?choose、when、otherwisel类似java的switch用法 从上到下的判断语句遇到满足的就用即使后续有条件也满足也不会调用 where标签具备自动添加where字符和删除首个子SQL语句and字符的功能
Test
public void GetBlogChoose_When_Otherwise() {SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);MapString, Object objectMap new HashMap();//注释掉就返回默认检索的所有情况//objectMap.put(title, 如何学Django);//objectMap.put(author, 刘);ListBlog blogIf mapper.getBlogChoose_When_Otherwise(objectMap);for (Blog blog : blogIf) {System.out.println(blog);}sqlsession.close();
}动态SQL-Set
public interface UserDao {int updateBlogSet(MapString, Object map);
}update idupdateBlogSet parameterTypemapupdate learn_mybatis.blogsetif testtitle ! nulltitle #{title},/ifif testauthor ! nullauthor #{author},/if/setwhere id #{id}
/update-- 若传入空的map或仅仅有id的map真实的sql语句
报错-- 若传入的map带有title键真实的sql语句
update learn_mybatis.blog SET title ? where id ?-- 若传入的map带有title键和author键真实的sql语句
update learn_mybatis.blog SET title ?, author ? where id ?set标签具备补充set字符和删除sql语句末尾“,”字符的功能if标签中sql子句末尾的“,”需要写入不然sql语句报错
Test
public void UpdateBlogSet() {SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);MapString, Object objectMap new HashMap();objectMap.put(id, 1);objectMap.put(title, 如何学Python-修改);objectMap.put(author, 刘);int blogIf mapper.updateBlogSet(objectMap);System.out.println(blogIf);sqlsession.commit();sqlsession.close();
}动态SQL-trim、sql片段
public interface UserDao {int updateBlogTrim(MapString, Object map);
}sql idif-title-authorif testtitle ! nulltitle #{title},/ifif testauthor ! nullauthor #{author},/if
/sqlupdate idupdateBlogTrim parameterTypemapupdate learn_mybatis.blogtrim prefixSET suffixOverrides,include refidif-title-author/include/trimwhere id #{id}
/update-- 若传入空的map或仅仅有id的map真实的sql语句
报错-- 若传入的map带有title键真实的sql语句
update learn_mybatis.blog SET title ? where id ?-- 若传入的map带有title键和author键真实的sql语句
update learn_mybatis.blog SET title ?, author ? where id ?trim标签可以自定义待拼接sql语句的相关前缀、后缀的补充操作及去除操作上述用trim标签实现set标签的相关功能
trim标签属性描述prefix给sql语句拼接的前缀suffix给sql语句拼接的后缀prefixOverrides去除sql语句前面的关键字或者字符该关键字或者字符由prefixOverrides属性指定假设该属性指定为AND当sql语句的开头为ANDtrim标签将会去除该ANDsuffixOverrides去除sql语句后面的关键字或者字符该关键字或者字符由suffixOverrides属性指定假设该属性指定为,“当sql语句的结尾为”,“trim标签将会去除该”,
// 使用trim标签和SQL片段
Test
public void UpdateBlogTrim_SQLFragment() {SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);MapString, Object objectMap new HashMap();objectMap.put(id, 1);objectMap.put(title, 如何学Python-修改);objectMap.put(author, 青-修改-修改);int blogIf mapper.updateBlogTrim(objectMap);System.out.println(blogIf);sqlsession.commit();sqlsession.close();
}动态SQL-foreach
public interface UserDao {ListBlog getBlogForeach(MapString, Object map);
}select idgetBlogForeach parameterTypemap resultTypeGSF.Example.Pojo.Blogselect * from learn_mybatis.blogwhereforeach collectionids itemid openand ( close) separatororid#{id}/foreach/where
/select-- 若传入空的map真实的sql语句
select * from learn_mybatis.blog-- 若传入的map中的list带有值1真实的sql语句
select * from learn_mybatis.blog WHERE ( id? )-- 若传入的map中的list带有值1、2、3真实的sql语句
select * from learn_mybatis.blog WHERE ( id? or id? or id? )提供遍历操作还是传入的map只是map的键对应的值是一个list
Test
public void GetBlogForeach() {SqlSession sqlsession MybatisUtils.getSqlsession();UserDao mapper sqlsession.getMapper(UserDao.class);ArrayListInteger ids new ArrayList();ids.add(1);ids.add(2);ids.add(3);ids.add(4);HashMapString, Object map new HashMap();map.put(ids, ids);ListBlog blogIf mapper.getBlogForeach(map);for (Blog blog : blogIf) {System.out.println(blog);}sqlsession.close();
}缓存
简介
什么是缓存
存在内存中的临时数据将用户经常查询的数据放在缓存内存中用户去查询数据就不用了从磁盘上关系型数据库数据文件查询从缓存中查询从而提高查询效率解决了高并发系统的性能问题
为什么使用缓存
减少和数据库的交互次数较少系统开销提高系统效率
什么样的数据能使用缓存
经常查询而且不经常改变的数据
Mybatis缓存
MyBatis包含一个非常强大的查询缓存特性它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存一级缓存和二级缓存
默认情况下只有一级缓存开启 (SqlSession级别的缓存也称为本地缓存)二级缓存需要手动开启和配置他是基于namespace级别的缓存为了提高扩展性MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
一级缓存 也称为本地缓存 与数据库同一次会话期间查询到的数据会放在本地缓存中以后如果需要获取相同的数据直接从缓存中拿没必须再去查询数据库 测试验证一级缓存
Test
public void test(){SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.queryUserById(1);System.out.println(user);System.out.println();User user2 mapper.queryUserById(1);System.out.println(user2);System.out.println(useruser2);sqlSession.close();
}返回结果为true且只执行了一次sql语句
一级缓存失效条件
查询不同的东西增删改操作可能会改变原来的数据所以必定会刷新缓存查询不同的Mapper.xml手动清理缓存
Test
public void test(){SqlSession sqlSession MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.queryUserById(1);System.out.println(user);// 更新数据导致缓存时效//mapper.updateUser(new User(2,niahoooo,309487));// 手动清理缓存导致缓存时效//sqlSession.clearCache();System.out.println();User user2 mapper.queryUserById(1);System.out.println(user2);System.out.println(useruser2);sqlSession.close();
}一级缓存生命周期
生命周期为一个特定mapper.xml的一次sqlsession会话
二级缓存 二级缓存也叫全局缓存一级缓存作用域太低了所以诞生了二级缓存 基于namespace级别的缓存一个名称空间对应一个二级缓存 工作机制 一个会话查询一条数据这个数据就会被放在当前会话的一级缓存中如果当前会话关闭了这个会话对应的一级缓存就没了一级缓存中的数据被保存到二级缓存中新的会话查询信息就可以从二级缓存中获取内容不同的mapper.xml查出的数据会放在自己对应的缓存(map)中 测试验证二级缓存
在全局开启二级缓存mybatis-config.xml
setting namecacheEnable valuetrue/在要开启缓存的mapper.xml中开启
cache evictionFIFOflushInterval60000size512readOnlytrue/测试
Test
public void test(){SqlSession sqlSession MybatisUtils.getSqlSession();SqlSession sqlSession2 MybatisUtils.getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);User user mapper.queryUserById(1);System.out.println(user);UserMapper mapper2 sqlSession2.getMapper(UserMapper.class);User user2 mapper.queryUserById(1);System.out.println(user2);System.out.println(useruser2);sqlSession.close();sqlSession2.close();
}注意
我们需要将实体类序列化(实现Serializable接口)否则就会报错sqlsession关闭的时候一定要在最后关闭不能先关闭sqlsession再关闭sqlsession2这样会导致Cause: org.apache.ibatis.executor.ExecutorException: Executor was closed
二级缓存的生命周期
在同一个Mapper.xml下的多次Sqlsession
只有当sqlsession关闭的时候数据才会从一级缓存扔到二级缓存
Mybatis调用顺序
先看二级缓存中有没有再看一级缓存中有没有查询数据库 一二级缓存都没有查询数据库查询后将数据放入一级缓存
自定义缓存-ehcache
介绍
EhCache 是一个纯Java的进程内缓存框架具有快速、精干等特点是Hibernate中默认的CacheProviderEhcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存
具体使用用到再说开发中常用Redis数据库来做缓存