mybaties学习笔记
mybatis框架 持久层
Spring
Spring MVC 表示层
shiro 安全框架
git 版本控制工具
项目阶段
Junit
使用Junit做单元测试的目的:
方便运行代码,人为查看结果符不符合预期
使用断言测试让机器去判断结果符不符合预期,a开头的很多junit断言测试
User one = UserDao.getOne(1); asserEquals(null,one);
@Test注释的方法成为测试用例
测试注解使用的要求:
要注解在某个方法上
该方法要求无参,返回值为空,且为public
在test里面添加参数
@Test(timeout=1000)
限时测试:timeout属性指定毫秒值,要求该单元测试用例在规定时间内完成
@Before
作用于某个方法上
作用:所有的测试单元执行之前执行该方法,每执行一个测试单元就会执行一次Before
要求:
要注解在某个方法上
该方法要求无参,返回值为空,且为public
@After
作用于某个方法上
作用:在所有单元测试用例之后执行该方法(多用于资源回收)
要求:
要注解在某个方法上
该方法要求无参,返回值为空,且为public
@BeforeClass
在整个测试类的所有测试用例运行之前运行一次
要注解在某个方法上
该方法要求无参,返回值为空,还要被public static修饰!!
@AfterClass
在整个测试类的所有测试用例运行完之后运行一次
要注解在某个方法上
该方法要求无参,返回值为空,还要被public static修饰!!
@Ignore
忽略这个测试用例,但是会在总计结果中显示统计信息
@Runwith()
套件测试,同时测试多个测试类。所谓Runner提供单元你测试运行的环境,默认为Junit4.class
@RunWith(Suite.class) @Suite.SuiteClasses(UserDaoImplTest.class,AppTest.class)
@Suite.SuiteClasses指定该套件中包含了哪些测试类
1.简介
MyBatis 是一款优秀的持久层框架
它支持自定义 SQL、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.1.获取mybaties
maven仓库:https://mvnrepository.com/artifact/org.mybatis/mybatis
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version> </dependency>
github
官方中文文档:https://mybatis.org/mybatis-3/zh/index.html
1.2.持久层
Dao层(数据库操作层),Service层(业务层),Control层(专门接收用户请求层)。
持久层:完成持久化工作的代码块
层是界限十分明显的
持久化是一个动作,持久层是一个概念。
1.3.为什么需要Mybatis
方便
传统的JDBC太复杂,简化,框架,自动化
帮助程序员将数据存入到数据库中
不用mybatis也可以,更容易上手
用的人特别多
spring,spring mvc,springboot
2.第一个mybatis程序
步骤:搭建环境-》导入mybatis-》编写代码-》测试
搭建数据库环境
2.1导入xml依赖
<dependencies> <!-- mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency> <!-- mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency> <!-- 测试工具junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version><scope>test</scope></dependency> </dependencies>
2.2.创建一个maven子项目
配置mybatis的核心配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--configuration核心配置文件--> <configuration> <!-- environments配置多个环境--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/> <!-- 在xml中&符号需要进行转义&--><property name="url" value="jdbc:mysql:///mybatis"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments> </configuration>
2.3编写mybatis工具类
//第一步从 XML 中构建 SqlSessionFactory public class MybatisUtil {private static SqlSessionFactory sqlSessionFactory;static {try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}//第二步既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();} }
2.4编写代码
实体类
public class User {private int id;private String name;private String password; 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 getPassword() {return password;} public void setPassword(String password) {this.password = password;} public User() {} public User(int id, String name, String password) {this.id = id;this.name = name;this.password = password;} @Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", password='" + password + '\'' +'}';} }
Dao接口
public interface UserDao {List<User> getUserList(); }
接口实现类
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace命名空间绑定一个Maper接口--> <mapper namespace="com.liu.Dao.UserDao"> <!-- id对应UserDao的方法,resultType对应实体类--><select id="getUserList" resultType="com.liu.Pojo.User">select * from mybatis.user</select> </mapper>
2.5测试
注意:
org.apache.ibatis.binding.BindingException: Type interface com.liu.Dao.UserMaper is not known to the MapperRegistry.
MapperRegistry是什么?
核心配置文件中注册mapers
junit测试
public class UserDaoTest {@Testpublic void test() {//第一步获取sqlSession对象SqlSession sqlSession = MybatisUtil.getSqlSession();//执行SQL//方式一getMapperUserMaper mapper = sqlSession.getMapper(UserMaper.class);List<User> userList = mapper.getUserList(); for (User user : userList) {System.out.println(user);}//关闭sqlSessionsqlSession.close();} }
可能遇到的问题:
1.配置文件没有注册
2.绑定接口错误
3.方法名不对
4.返回类型不对
5.Maven导出资源问题
3.CRUD
1.namespace
namespace中的包名要和Mapper接口的报名一致
2.select
选择,查询语句;
id:就是对应namespace中的方法名
resulType:sql语句执行的返回值!
paramterType:参数类型!
1.编写接口
2.编写对应的mapper中的sql
3.测试
3.Insert
UserMapper:
//插入一条记录public void insertOne(User user);
UserMapper.xml
<insert id="insertOne" parameterType="com.liu.Pojo.User">insert into user values (#{id},#{name},#{password})</insert>
Test:
//插入用户@Testpublic void insertOne(){SqlSession sqlSession = MybatisUtil.getsqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.insertOne(new User(4,"liulang","123456")); //提交事务sqlSession.commit();sqlSession.close();}
4.Update
UserMapper:
//修改记录public int alterUser(User user);
UserMapper.xml
<update id="alterUser" parameterType="com.liu.Pojo.User">update user set name=#{name},password=#{password} where id=#{id};</update>
Test:
//修改信息@Testpublic void alterUser(){SqlSession sqlSession = MybatisUtil.getsqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class);int i = mapper.alterUser(new User(4, "liulang", "123"));if (i>0)System.out.println("修改成功");elseSystem.out.println("修改失败"); //提交事务sqlSession.commit();sqlSession.close();}
5.Delete
UserMapper:
//删除用户public int deleteUser(int id);
UserMapper.xml
<delete id="deleteUser" parameterType="int">delete from user where id=#{id}</delete>
Test:
//删除用户@Testpublic void deleteUser(){SqlSession sqlSession = MybatisUtil.getsqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class);int i = mapper.deleteUser(4);if (i>0)System.out.println("删除成功");elseSystem.out.println("删除失败"); //提交事务sqlSession.commit();sqlSession.close();}
注意:增删改都需要提交事务才会生效!!! sqlSession.commit();
6.错误
namespace="com.liu.Mapper.UserMapper";必须写详细路径
sql语句标签错误
注册mapper;resource的路径要用/而不是点
<mappers><mapper resource="com/liu/Mapper/UserMapper.xml"/> </mappers>
4.maven资源导出问题
<build><resources> <!-- 设置正常情况的resources目录下的properties文件--><resource> <!-- 配置路径--><directory>src/main/resources</directory><includes> <!-- 包含什么文件--><include>**/*.properties</include><include>**/*.xml</include></includes></resource> <!-- 设置java路径的properties文件--><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes></resource></resources></build>
7.非常实用的Map
如果我们的实体类或数据中的表,字段过多,我们考虑使用Map。
修改或添加部分信息:
UserMapper:
//使用map修改部分数据public int alterUser2(Map<String,Object> map);
UserMapper.xml
<update id="alterUser2" parameterType="map">update user set name=#{username} where id=#{userid};</update>
Test:
//使用map更新部分信息@Testpublic void alterUser2(){SqlSession sqlSession = MybatisUtil.getsqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String, Object> map = new HashMap<String, Object>();map.put("username","李小盛");map.put("userid",3);int i = mapper.alterUser2(map);if (i>0)System.out.println("修改成功");elseSystem.out.println("修改失败"); //提交事务sqlSession.commit();sqlSession.close();}
根据多个条件查询信息:
UserMapper:
//指定多条件查询public User getUserById2(Map<String,Object> map);
UserMapper.xml
<select id="getUserById2" parameterType="map" resultType="com.liu.Pojo.User">select * from user where id=#{id} and name=#{name}</select>
Test:
@Testpublic void getUserById2(){SqlSession sqlSession = MybatisUtil.getsqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String, Object> map = new HashMap<String, Object>();map.put("id",3);map.put("name","李小盛");User user = mapper.getUserById2(map); System.out.println(user); sqlSession.close();}
Map传递参数,直接在sql中取出key即可。
使用Map的时候一定要注意map里面的键值对必须和UserMapper.xml中使用的变量对应!!!
对象传递参数,直接在sql中去对象的属性。
只有一个基本数据类型参数的情况下,可以直接在sql中使用
多个参数用map或注解!
8.模糊查询
1.java执行的时候传递通配符%
List<User> users = mapper.likeUser("%李%");
2.在sql拼接中使用通配符
<select id="likeUser" resultType="com.liu.Pojo.User">select * from user where name like "%"#{name}"%" </select>
第二种写法:
<select id="queryAll" resultMap="USER" parameterType="map">select * from user<where><if test="name!=null">name like '%${name}%'</if></where> </select>
4.XML配置
1.核心配置文件
mybaits-config,xml
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
2.环境配置
Mybatis可以配置成适应多环境
注:尽管可以配置多个环境,但是每个sqlSessionFactory实例只能选择一种环境
学会使用配置多套运行环境!
Mybatis默认的事务管理器就是JDBC,连接池:POOLED
3.属性(properties)
通过propertis来引入配置文件
1.编写一个配置文件:
driver=com.mysql.jdbc.Driver url=jdbc:mysql:///mybatis username=root password=123456
2.在核心配置文件中引入:在核心配置文件中所有的标签都有规定的先后顺序
资源在核心配置同一个路径下可以使用相对路径定位
没有添加额外参数 <properties resource="db.properties"/> 添加额外参数 <properties resource="db.properties"><property name="username" value="root1"/><property name="password" value="123456"/></properties>
可以直接引入配置文件
可以在其中增加一些配置属性
如果两种方式有相同的属性,优先使用外部配置文件的属性!!!
4.类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写
第一种方式:
<typeAliases><typeAlias type="com.liu.Pojo.User" alias="User"/></typeAliases>
第二种方式
可以指定一个包名,Mybatis会在这个包名下面搜索需要的JavaBean,比如:
扫描的实体类的名称,它的默认别名就是这个类的首字母小写。
<typeAliases><package name="com.liu.Pojo"/></typeAliases>x
在实体类比较少的情况使用第一种,
如果实体类十分多的时候,建议第二种
第一种可以DIY别名,第二种不行。如果非要在实体类上增加注解,注解方式大于默认搜索
@Alias("hello") public class User(){};
5.映射器(mappers)
MapperRegistry:注册绑定我们需要的Mapper文件
方式一:【推荐使用】
<mappers><mapper resource="com/liu/Mapper/UserMapper.xml"/></mappers>
方式二:使用class方式绑定注册
<mappers><mapper class="com.liu.Mapper.UserMapper"/></mappers>
方式三:使用包扫描注册绑定
<mappers><package name="com.liu.Mapper"/></mappers>
方式二和方式三注意!!:
接口和它的Mapper配置文件必须同名
接口和它的Mapper配置文件必须在同一个包下面
6.生命周期
生命周期类和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder:
一旦创建了SqlSessionFactory就不在需要他了
局部变量
SqlSessionFactory:
可以想象为数据库连接池
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
因此 SqlSessionFactory 的最佳作用域是应用作用域。(程序开始他就开始,程序结束他就结束)
简单的就是使用单例模式或者静态单例模式。
SqlSession:
连接到连接池的一个请求!
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
用完之后赶紧关闭,否则资源被占用
每一个Mapper代表一个具体的业务。
5.解决属性名和字段名不一致的问题
解决方法:
起别名
<select id="getUserById" parameterType="int" resultType="com.liu.Pojo.User">select id,name,password as pwd from user where id = #{id}</select>
2.resultMap
结果集映射
id name password id name pwd
resultMap
元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets
数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
<!-- resultMap就是使用这里的id,类型映射为实体类 --><resultMap id="UserMap" type="User"> <!-- property表示实体类属性,column表示数据库字段映射。将字段映射为实体类的对应属性 --><result property="id" column="id"/><result property="name" column="name"/><result property="pwd" column="password"/> </resultMap><select id="getUserList" resultMap="UserMap">select * from user</select>
6.日志
6.1日志工厂
如果一个数据库操作出现了异常,我们需要排错。日志就是我们最好的助手。
曾经:sout、debug
现在:日志工厂!
SLF4J
LOG4J【掌握】
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING【掌握】
NO_LOGGING
在Mybatis中具体使用哪一个日志实现,在设置中设定!
STDOUT_LOGGING:标准日志输出
配置设置的时候一定要注意格式、大小写、空格等问题
<settings><setting name="logImpl" value="STDOUT_LOGGING"/></settings>
6.2Log4j
Apache的开源项目log4j是一个功能强大的日志组件,提供方便的日志记录。
日志可以输出到控制到或GUI组件
我们可以控制每一条日志输出的格式
通过设置每一条日志的级别,我们能够更细致的控制日志生成的过程。
通过配置文件来进行配置,不需要我们修改应用的代码
1.导入LOG4J的包
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version> </dependency>
2.log4j.properties
### 配置根 ### #配置日志类型 log4j.rootLogger = debug,console ,file### 设置输出sql的级别,其中logger后面的内容全部为jar包中所包含的包名 ### log4j.logger.org.apache=debug log4j.logger.java.sql.Connection=debug log4j.logger.java.sql.Statement=debug log4j.logger.java.sql.PreparedStatement=debug log4j.logger.java.sql.ResultSet=debug### 配置输出到控制台 ### 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.RollingFileAppender log4j.appender.file.File = ./logs/mybatis.log log4j.appender.file.Append = true log4j.appender.file.Threshold = DEBUG log4j.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#日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG #log4j.logger.java.sql.Statement=DEBUG #log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PraparedStatement=DEBUG
3.配置log4j为日志的实现
<settings><setting name="logImpl" value="LOG4J"/></settings>
4.Log4j的使用,直接测试运行查询就行了
简单使用
1.在需要使用log4j的类中,导入包,包不要导错了,需要导入apeach的log4j
2.生成日志对象,加载参数为当前类的class
static Logger logger = Logger.getLogger(mybatistest.class);
3.日志级别
logger.info("info:进入testlog4j"); logger.debug("debug:进入testlog4j"); logger.error("error:进入testlog4j");
7.分页
为什么要分页?
减少数据的处理量
#{参数名}:按照preparedstatement解析sql语句时所使用的的?占位符
${参数名}:传什么参数,就按字符串拼接方式进行填充
7.1使用limit分页,语法:
select * from user limit statIndex,pagesize;select * from user limit 2,5 select * from user limit 3
使用mybatis实现分页,核心SQl
1.接口
//分页查询 public List<User> limitUser(Map<String,Integer> map);
2.Mapper.xml
<!-- 实现分页查询--><select id="limitUser" parameterType="map" resultType="user">select * from user limit #{startIndex},#{pageSize}</select>
3.测试
//分页查询 @Test public void limitUser(){SqlSession sqlSession = MybatisUtil.getsqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);HashMap<String, Integer> map = new HashMap<String, Integer>();map.put("startIndex",0);map.put("pageSize",3);List<User> users = mapper.limitUser(map);for (User user : users) {System.out.println(user);} }
7.2useGeneratedKeys
如果想要拿到插入数据后自动递增的主键值时,使用useGeneratedKeys=true
KeyColumn:指定自动递增的列明
KeyProperty:指定传入的参数对象中用于存放自动递增的值对应的属性
8.使用注解开发
8.1面向接口编程
接口定义与实现的分离
接口的本身反应了系统设计人员对系统的抽象理解
接口也应有两个类:
一个是对一个个体的抽象abstract
一个是对个体某个方面的抽象interface
8.2使用注解开发
1.注解直接在接口上实现
@Select("select * from user") List<User> getUsers();
2.需要在核心配置文件中绑定接口!
<mappers><mapper class="com.liu.Mapper.UserMapper2"/> </mappers>
3.测试
//注解方式 @Test public void zjUsers(){SqlSession sqlSession = MybatisUtil.getsqlSession();UserMapper2 mapper = sqlSession.getMapper(UserMapper2.class);List<User> users = mapper.getUsers();for (User user : users) {System.out.println(user);}sqlSession.close(); }
本质:反射机制实现
底层:动态代理
8.3CRUD
我们可以在工具类创建的时候实现自动提交事务!
return sqlSessionFactory.openSession(true);
编写接口,增加注解
//方法存在多个参数时,所有的参数前面必须加上@Param("id")注解@Select("select * from user where id=#{id} and name=#{name}")public User getUserById(@Param("id") int id,@Param("name") String username);@Insert("insert into user values (#{id},#{name},#{password})")public int addUser(User user);@Update("update user set name=#{name},password=#{password} where id=#{id}")int UpdateUser(User user);@Delete("delete from user where id=#{id}")public int delUser(@Param("id") int pid);
【我们必须将接口绑定到注册到我们的核心配置文件中】
<mappers><package name="com.liu.Mapper"/></mappers>
关于@Param(")注解
基本类型的参数或则String类型的参数需要加上
引用数据类型不需要加
如果只有一个数据类型的话可以忽略,建议也加上
我们在SQL中引用的就是我们这里的@Param设置的属性名
#{}和${}区别:
#{}和${}这两个语法是为了动态传递参数而存在的,是Mybatis实现动态SQL的基础
#{} 是 占位符 :动态解析 -> 预编译 -> 执行
${} 是 拼接符 **:动态解析 -> 编译 -> 执行
类似statement和preparestatement
9.Lombok
java library
plugs
build tools
使用步骤:
1.在IDEA安装plug,Lombok插件
2.在maven中导入Lombok依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.20</version></dependency>
@Data:,toString,GetandSet,hashcode,equals
@AllArgsConstructor @NoArgsConstructor
全参构造和无参构造
3.在实体类上加注解即可
10.多对一
对学生来说,关联,多个学生关联一个老师【多对一】
对老师而言,集合,一个老师辅导多个学生【一对多】
环境搭建:
1.导入Lombok
2.新建实体类Teacher,Student
3.建立Mapper接口
4.建立Mapper.xml文件
5.在核心配合文件中绑定Mapper接口或文件
6.测试
需求查询所有的学生信息以及对应的老师信息。
1.按照查询嵌套处理
<!-- 使用结果集映射需要使用resultMap--> <select id="getStudent" resultMap="StudentTeacher">select * from student </select> <resultMap id="StudentTeacher" type="student"><!-- 复杂的属性,我们需要单独处理--><!-- 对象使用association--><result property="id" column="id"/><result property="name" column="name"/><association property="teacher" column="id" javaType="Teacher" select="getTeacher"/><!-- 集合使用collection--><!-- <collection property=""--> </resultMap><select id="getTeacher" resultType="teacher">select * from teacher where id=#{id} </select>
第二条select语句中的where里面的条件#{},花括号里面随便写都不会影响查询结果
2.按照结果嵌套处理
<!-- 按照结果嵌套处理--> <select id="getStudent2" resultMap="StudentTeacher2">select s.id sid,s.name sname,t.name tnamefrom student as s,teacher as t where s.id=t.id </select><resultMap id="StudentTeacher2" type="student"><result column="sid" property="id"/><result column="sname" property="name"/><association property="teacher" javaType="Teacher"><result property="tid" column="id"/><result property="name" column="tname"/></association> </resultMap>
查询结果:
Student(id=1, name=liulang, cno=1, teacher=Teacher(id=1, name=chentao, cno=1)) Student(id=2, name=lixiaosheng, cno=1, teacher=Teacher(id=1, name=chentao, cno=1)) Student(id=3, name=zhenghaiqing, cno=1, teacher=Teacher(id=1, name=chentao, cno=1))
11.一对多
一个老师拥有多个学生
1.结果集映射
<select id="getTeacher2" resultMap="TeacherStudent">select s.id sid,s.name sname,t.name tname,t.id tid,t.cno tcno,s.cno scnofrom student s,teacher t where s.cno=t.cno </select> <resultMap id="TeacherStudent" type="teacher"><result property="id" column="tid"/><result property="cno" column="tcno"/><result property="name" column="tname"/><collection property="students" ofType="student"><result property="id" column="sid"/><result property="cno" column="scno"/><result property="name" column="sname"/></collection> </resultMap>
2.子查询方式
<!-- 子查询--><select id="getTeacher" resultMap="TeacherStudent1">select * from teacher</select><resultMap id="TeacherStudent1" type="Teacher"><result property="id" column="id"/><result property="name" column="name"/><result property="cno" column="cno"/> <!-- column用户传递给子查询作为where条件 --><collection property="students" column="cno" javaType="ArrayList" ofType="Student" select="getStudent"/></resultMap><select id="getStudent" resultType="Student">select * from student where cno=#{cno}</select>
查询结果:
Teacher(id=1, name=chentao, cno=1, students=[Student(id=1, name=liulang, cno=1), Student(id=2, name=lixiaosheng, cno=1), Student(id=3, name=zhenghaiqing, cno=1)])
总结:
1.关联-association【多对一】
2.集合-collection【一对多】
3.javaType & ofType
1.javaType用来指定实体类中属性的类型
2.ofTyp用来指定映射到list或则集合中的pojo类型,泛型中的集合类型
注意:
保证SQL的可读性,尽量保证通俗易懂
注意一对多和多对一中,属性名和字段的问题
如果问题不好排查,可以使用日志,建立使用log4j
12.动态SQL
什么是动态SQL:根据不同的条件生成不同的SQL语句
所谓动态SQL:本质还是SQL语句,只是我们可以再SQL层面,去执行一个逻辑代码
1.搭建环境
开启驼峰命名:只应用于数据库映射java使用的驼峰命名
<settings><!-- 开启驼峰命名映射--><setting name="mapUnderscoreToCamelCase" value="true"/></settings>
2.where
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
使用where标签如果你满足的第一个条件在where 后面添加了一个and,会被这个标签自动删除and然后正常执行,如果你没有过滤条件,那么where标签会将where字句删除
<where><if test="state != null">state = #{state}</if><if test="title != null">AND title like #{title}</if><if test="author != null and author.name != null">AND author_name like #{author.name}</if></where>
3.IF
BlogMapper.xml
<insert id="addBlog" parameterType="blog">insert into blog values(#{id},#{title},#{author},#{createTime},#{view});</insert><select id="queryBlogIf" parameterType="map" resultType="blog">select * from blog where 1=1<if test="title != null">and title=#{title}</if><if test="author != null">and author = #{author}</if></select>
test:
public void queryBlogIf(){SqlSession sqlSession = MybatisUtil.getsqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);HashMap map = new HashMap();map.put("title","Mybatis"); // map.put("author","ll");List<Blog> blogs = mapper.queryBlogIf(map);for (Blog item : blogs) {System.out.println(item);}sqlSession.close();}
4.choose(swtich)
<select id="queryBlogChoose" resultType="blog" parameterType="map">select * from blog<where><choose><when test="title != null">title=#{title}</when><when test="author != null">author=#{author}</when><otherwise>view > 0</otherwise></choose></where></select>
作用:和java的swtich功能类似
只会满足其中之一,如果存在满足多个条件的话也只会满足第一个条件
5.Set
作用:set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号```xml
<update id="updateBlogSet" parameterType="map" >update blog<set><if test="title != null">title=#{title},</if><if test="author != null">author=#{author},</if><if test="view != null">view=#{view},</if></set>where id = '35a166859fb84884b1e18732a05516ff' </update>
6.foreach(几乎不用)
我们想查出数据库前两条数据
<select id="queryfreeBlog" resultType="Blog">select * from Blog<where><foreach collection="list" item="id" open="and (" close=")" separator="or">id = #{id}</foreach></where></select>
open:循环开始之前拼接的内容;
close结:循环结束拼接的内容
separator:指定循环中的分隔符
collection:循环遍历的内容
item:遍历的单个变量,在标签体重来使用
@Testpublic void queryfreeBlog(){SqlSession sqlSession = MybatisUtil.getsqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);HashMap map = new HashMap();ArrayList<String> str = new ArrayList<String>();str.add("35a166859fb84884b1e18732a05516ff");str.add("6d5cb2ff745c4f658eefd4b21add44f9");map.put("list",str);List<Blog> blogs = mapper.queryfreeBlog(map);for (Blog blog : blogs) {System.out.println(blog);}sqlSession.close();}
结果:
Blog{id='35a166859fb84884b1e18732a05516ff', title='这不是结局', author='小新', createTime=2021-07-29, view=998} Blog{id='6d5cb2ff745c4f658eefd4b21add44f9', title='java', author='刘星', createTime=2021-07-29, view=1005}
注意:
如果这里我们没有传递任何参数,就会自动删除where条件,将会查出所有信息
7.SQL片段
有的时候,我们可能会将一些功能的部分抽取出来,方便复用
<sql id="if-author-title"><if test="title != null">and title=#{title}</if><if test="author != null">and author = #{author}</if></sql><select id="queryBlogIf" parameterType="map" resultType="blog">select * from blog<where><include refid="if-author-title"/></where></select>
实现代码的复用
使用sql标签提取公共部分
在使用的地方用include标签引入SQL片段通过id引入
注意:
最好基于单表来定义SQL片段
不要存在where标签
最好只要一些IF判断就好了
13.缓存(了解)
1.什么是缓存?
存在内存中的临时数据
将用户数据查询到的数据放在缓存中,用户去查询数据就不用从磁盘上查询,从缓存中读取,从而提高效率,解决了高并发系统的性能问题
2.为什么要使用缓存?
减少和数据库的交互次数,减少系统开销,提高系统效率
3.什么样的数据能使用缓存?
查询:连接数据库,耗内存
解决:一次查询的结果,给他暂存在一个可以直接读取的地方--》内存:缓存
我们再次查询相同数据的时候我们走缓存,就不用走数据库了。
14.Mybatis缓存
Mybatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存,缓存可以极大地提升查询效率
Mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
默认情况下,只有一级缓存开启。(本地缓存)
二级缓存需要手动开启和配置,他是基于namespace级别的缓存
为了提高扩展性,mybatis定了缓存接口Cache,我们可以通过实现Cache接口来定义二级缓存
一级缓存
一级缓存也叫本地缓存
与数据库同义词会话期间查询到的数据会被放在本地缓存中
以后如果需要获取相同的数据的话,直接从缓存中拿,没有必要在去查数据库
实验步骤
1.开启日志
2.测试在一个Session中查询两次相同的记录
3.查看日志输出
@Testpublic void queryAllUser(){SqlSession sqlSession = MybatisUtil.getsqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> users = mapper.queryAllUser(6);System.out.println(users);System.out.println("=============================================");List<User> users1 = mapper.queryAllUser(6);System.out.println(users1);System.out.println(users==users1);sqlSession.close();}
增删改会刷新原来的东西
缓存失效的情况:
增删改都有可能改变原来的数据,必定会刷新缓存
查询不同的Mapper.xml
手动清理缓存
查询不同的东西
小结:一级缓存默认是开启的,只在一次SqlSessionFactory中有效,也就是拿到链接到关闭连接区间有效。一级缓存也是无法关闭的。
一级缓存作用域就是sqlsession对象,存储的内容,查询后的结果集,在sqlSession对象中有Map结果,Map的值就是结果集的对象。
二级缓存
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
基于namespace级别的缓存,一个名称空间,对应一个二级缓存
工作机制:
一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
如果当前会话关闭了,这个会话对应的一级缓存就没有了;但是我们想要的是,会话关闭了,一级缓存中的数据会被保存到二级缓存中
新的会话查询信息,就可以从二级缓存中获取内容;
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:<cache/>
步骤:
1.开启缓存设置
<setting name="cacheEnabled" value="true"/>
2.要是用二级缓存需要在Mapper中开启
<!--在当前的xml中开启二级缓存--><cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
也可以自定义一些参数
3.测试
@Testpublic void queryAllUser(){SqlSession sqlSession1 = MybatisUtil.getsqlSession();SqlSession sqlSession2 = MybatisUtil.getsqlSession();UserMapper mapper = sqlSession1.getMapper(UserMapper.class);List<User> users = mapper.queryAllUser(6);System.out.println(users);sqlSession1.close();UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);List<User> users2 = mapper2.queryAllUser(6);System.out.println(users2);sqlSession2.close();}
只进行了一次查询
小结:二级缓存只能在一个namespace内有效,也就是只在一个xml文件内。所有的数据都会先放在一级缓存中,只有当会话提交或关闭的时候转存到二级缓存
问题!:我们需要将实体类序列化
implements Serializable
查找顺序
自定义缓存--ehcache
ehcache是一种广发使用的开源java分布式缓存
Mybatis注意点
mybatis-config.xml:
MybatisUtil.java
UserMapper.xml
mybaties学习笔记相关推荐
- PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call
您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...
- 容器云原生DevOps学习笔记——第三期:从零搭建CI/CD系统标准化交付流程
暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...
- 容器云原生DevOps学习笔记——第二期:如何快速高质量的应用容器化迁移
暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...
- 2020年Yann Lecun深度学习笔记(下)
2020年Yann Lecun深度学习笔记(下)
- 2020年Yann Lecun深度学习笔记(上)
2020年Yann Lecun深度学习笔记(上)
- 知识图谱学习笔记(1)
知识图谱学习笔记第一部分,包含RDF介绍,以及Jena RDF API使用 知识图谱的基石:RDF RDF(Resource Description Framework),即资源描述框架,其本质是一个 ...
- 计算机基础知识第十讲,计算机文化基础(第十讲)学习笔记
计算机文化基础(第十讲)学习笔记 采样和量化PictureElement Pixel(像素)(链接: 采样的实质就是要用多少点(这个点我们叫像素)来描述一张图像,比如,一幅420x570的图像,就表示 ...
- Go 学习推荐 —(Go by example 中文版、Go 构建 Web 应用、Go 学习笔记、Golang常见错误、Go 语言四十二章经、Go 语言高级编程)
Go by example 中文版 Go 构建 Web 应用 Go 学习笔记:无痕 Go 标准库中文文档 Golang开发新手常犯的50个错误 50 Shades of Go: Traps, Gotc ...
- MongoDB学习笔记(入门)
MongoDB学习笔记(入门) 一.文档的注意事项: 1. 键值对是有序的,如:{ "name" : "stephen", "genda" ...
最新文章
- SpringBoot与SpringMVC的区别是什么?
- linux sw状态,linux 下查看性能状态命令
- swagger-bootstrap-ui 1.9.3 发布,i18n及自定义文档支持
- 【pl/sql番外篇】 存储过程 游标
- 程序员必知必会的十大排序算法
- matlab在电气信息类专业中的应用,MATLAB在电气信息类专业中的应用(高等学校应用型特色规划...
- Js + Css的msn式的popup提示窗口的实现 (转自:月牙儿)
- NodeJS学习笔记之express
- oracle 修改子分区,Oracle子分区(sub partition)操作
- 3. HTML DOM Attribute 对象
- 侠客密码查看器 v3.8 build 0615 绿色
- oracle自增序列
- 关于我如何解决了xlsm文件格式的问题
- 解决戴尔笔记本电脑插上耳机没反应,要重启才能识别
- 小米有品开出全球首家商业旗舰店:加速新零售扩张
- 体脂秤方案——体脂秤的原理是什么?
- noip2014 无线网路发射器选址 (模拟)
- 美国软件开发实习生月薪排行榜
- springboot使用undertow作为web容器而引发的中文乱码问题
- 简单易懂且有趣的pycharm运行小游戏
热门文章
- php调用微信公众号支付接口,Thinkphp微信公众号支付接口
- larval 进程管理
- unittestreport 详细功能使用文档(V1.1.1)——测试派柠檬班
- 解决richedit的内容不能超过64k的方法
- Vue ui/vue create创建项目报错:Failed to get response from https://registry.npmjs.org/vue-cli-version-ma
- Go语言学习培训靠谱吗
- 【5G系列】一文打尽 IMSI、TMSI、GUTI、P-TMSI、S-TMSI、LMSI、5G-TMSI、5G-GUTI、5G-S-TMSI
- 安信可SX1278LORA通讯试验
- 计算机专业抑郁症多,计算机算法能够辅助医生诊断抑郁症?
- mysql数据库统计人数_统计人数 数据库