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中&符号需要进行转义&amp--><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.错误

  1. namespace="com.liu.Mapper.UserMapper";必须写详细路径

  2. sql语句标签错误

  3. 注册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学习笔记相关推荐

  1. PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call

    您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...

  2. 容器云原生DevOps学习笔记——第三期:从零搭建CI/CD系统标准化交付流程

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  3. 容器云原生DevOps学习笔记——第二期:如何快速高质量的应用容器化迁移

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  4. 2020年Yann Lecun深度学习笔记(下)

    2020年Yann Lecun深度学习笔记(下)

  5. 2020年Yann Lecun深度学习笔记(上)

    2020年Yann Lecun深度学习笔记(上)

  6. 知识图谱学习笔记(1)

    知识图谱学习笔记第一部分,包含RDF介绍,以及Jena RDF API使用 知识图谱的基石:RDF RDF(Resource Description Framework),即资源描述框架,其本质是一个 ...

  7. 计算机基础知识第十讲,计算机文化基础(第十讲)学习笔记

    计算机文化基础(第十讲)学习笔记 采样和量化PictureElement Pixel(像素)(链接: 采样的实质就是要用多少点(这个点我们叫像素)来描述一张图像,比如,一幅420x570的图像,就表示 ...

  8. 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 ...

  9. MongoDB学习笔记(入门)

    MongoDB学习笔记(入门) 一.文档的注意事项: 1.  键值对是有序的,如:{ "name" : "stephen", "genda" ...

最新文章

  1. SpringBoot与SpringMVC的区别是什么?
  2. linux sw状态,linux 下查看性能状态命令
  3. swagger-bootstrap-ui 1.9.3 发布,i18n及自定义文档支持
  4. 【pl/sql番外篇】 存储过程 游标
  5. 程序员必知必会的十大排序算法
  6. matlab在电气信息类专业中的应用,MATLAB在电气信息类专业中的应用(高等学校应用型特色规划...
  7. Js + Css的msn式的popup提示窗口的实现 (转自:月牙儿)
  8. NodeJS学习笔记之express
  9. oracle 修改子分区,Oracle子分区(sub partition)操作
  10. 3. HTML DOM Attribute 对象
  11. 侠客密码查看器 v3.8 build 0615 绿色
  12. oracle自增序列
  13. 关于我如何解决了xlsm文件格式的问题
  14. 解决戴尔笔记本电脑插上耳机没反应,要重启才能识别
  15. 小米有品开出全球首家商业旗舰店:加速新零售扩张
  16. 体脂秤方案——体脂秤的原理是什么?
  17. noip2014 无线网路发射器选址 (模拟)
  18. 美国软件开发实习生月薪排行榜
  19. springboot使用undertow作为web容器而引发的中文乱码问题
  20. 简单易懂且有趣的pycharm运行小游戏

热门文章

  1. php调用微信公众号支付接口,Thinkphp微信公众号支付接口
  2. larval 进程管理
  3. unittestreport 详细功能使用文档(V1.1.1)——测试派柠檬班
  4. 解决richedit的内容不能超过64k的方法
  5. Vue ui/vue create创建项目报错:Failed to get response from https://registry.npmjs.org/vue-cli-version-ma
  6. Go语言学习培训靠谱吗
  7. 【5G系列】一文打尽 IMSI、TMSI、GUTI、P-TMSI、S-TMSI、LMSI、5G-TMSI、5G-GUTI、5G-S-TMSI
  8. 安信可SX1278LORA通讯试验
  9. 计算机专业抑郁症多,计算机算法能够辅助医生诊断抑郁症?
  10. mysql数据库统计人数_统计人数 数据库