Mybatis framework

Jm 2022-09-23 08:38:25 阅读数:274

mybatisframework

文章目录

一.Mybatis概述

1.1 框架

  • 在⽂seen in the offeringframeworkTranslated into framework
  • Java常⽤框架:
    • SSM三⼤框架:Spring + SpringMVC + MyBatis
    • SpringBoot
    • SpringCloud
    • 等等…
  • Framework is to pass⽤代码的封装,提前写好了⼀stacking⼝和类,We can do it in a⽬When direct speech⼊这些 接⼝和类(引⼊框架),Based on these existing meet⼝and class into⾏开发,可以⼤⼤提⾼开发效率.
  • 框架⼀Generally alljar包的形式存在.(jar包中有class⽂And various configuration⽂件等.)

1.2 三层架构

Can be turned hereJavaWebCheck out point seven!!
链接:Click here to transfer to see!

1.3 JDBC不足

  • SQL语句写死在Java程序中,不灵活.改SQLIf so, change itJava代码.违背开闭原则OCP.
  • 给?The value is tedious.
  • 将结果集封装成JavaObject is a cumbersome.

1.4 了解Mybatis

  • MyBatis本质上就是对JDBC的封装,通过MyBatis完成CRUD.
  • MyBatisIn three layer architecture is in charge of the persistence layer,属于持久层框架.
  • ORM:对象关系映射
    • O(Object):Java虚拟机中的Java对象
    • R(Relational):关系型数据库
    • M(Mapping):将Java虚拟机中的JavaObject is mapped to a database table⼀⾏记录,Or the database table ⼀⾏记录映射成Java虚拟机中的⼀个Java对象.
    • ORM图示
      在这里插入图片描述
    • MyBatis属于半⾃动化ORM框架.
    • Hibernate属于全⾃动化的ORM框架.
  • MyBatis框架特点:
    • ⽀持定制化 SQL、存储过程、Basic mapping, and⾼级映射
    • 避免了⼏乎所有的 JDBC 代码中⼿动设置参数以及获取结果集
    • ⽀持XML开发,也⽀The annotation type development.【为了保证sqlStatement flexibility,所以mybatis⼤Part is picked⽤ XML⽅式开发.】
    • 将接⼝和 Java 的 POJOs(Plain Ordinary Java Object,简单普通的Java对象)映射成数据库中的 记录
    • 体积⼩好学:两个jar包,两个XML配置⽂件.
    • 完全做到sql解耦合.
    • Provides the basic mapping label.
    • 提供了⾼level map label.
    • 提供了XML标签,⽀keep dynamicSQL的编写.

二.Mybatis入门程序

2.1 版本

软件版本:

  • IntelliJ IDEA:2022.2
  • MySQL数据库:8.0.30
    组件版本:
  • MySQL驱动:8.0.30
  • MyBatis:3.5.10
  • JDK:Java17
  • JUnit:4.13.2 Logback:1.2.11

2.2 MyBatis入门程序开发步骤

(可参考:Mybatis中文网

  • Write code before:
    • 准备数据库表:汽⻋表t_car,字段包括:
      • id:主键(⾃增)【bigint】
      • car_num:汽⻋编号【varchar】
      • brand:品牌【varchar】
      • guide_price:⼚home price guide【decimal类型,专⻔For financial data type】
      • produce_time:⽣birth time【char,年⽉⽇即可,10个⻓度,‘2022-10-11’】
      • car_type:汽⻋类型(燃油⻋、电⻋、氢能源)【varchar】
  • 步骤1:创建maven的java项目
  • 步骤2:引⼊依赖(mybatis依赖 + mysql驱动依赖)
    pom.xml
<!--mybatis核⼼依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
  • 步骤3:在resources根⽬录下新建mybatis-config.xml配置⽂件
    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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/po wernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--sql映射⽂Create good after,需要将该⽂A path configuration to this⾥-->
<mapper resource=""/>
</mappers>
</configuration>

注意1:mybatis核⼼配置⽂件的⽂Piece name no⼀定是mybatis-config.xml,Can be other name.
注意2:mybatis核⼼配置⽂A storage location also can.这⾥选择放在resources根下,Equivalent to the class 根路径下.

  • 步骤4:在resources根⽬录下新建CarMapper.xml配置⽂件
    CarMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespaceFeel free to write first⼀个-->
<mapper namespace="car">
<!--insert sql:保存⼀a steam⻋信息-->
<insert id="insertCar">
insert into t_car
(id,car_num,brand,guide_price,produce_time,car_type)
values
(null,'102','丰⽥mirai',40.30,'2014-10-05','氢能源')
</insert>
</mapper>

注意1:sqlThe last end can not write a statement“;”
注意2:CarMapper.xml⽂A name is not constant.可以使⽤other names.
注意3:CarMapper.xml⽂A location is random.这⾥选择放在resources根下,Equivalent to the class under the root of.
注意4:将CarMapper.xml⽂A path configuration tomybatis-config.xml:
mybatis-config.xml

<mapper resource="CarMapper.xml"/>
  • 步骤5:编写MyBatisIntroductionTest代码
    MyBatisIntroductionTest.java
package com.powernode.mybatis;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
/** * MyBatis⼊⻔程序 */
public class MyBatisIntroductionTest {

public static void main(String[] args) {

// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSession
FactoryBuilder();
// 2. 创建SqlSessionFactory对象
InputStream is = Thread.currentThread().getContextClassLoader().ge
tResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.bui
ld(is);
// 3. 创建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 执⾏sql
int count = sqlSession.insert("insertCar"); // 这个"insertCar"必须是
sql的id
System.out.println("插⼊⼏条数据:" + count);
// 5. 提交(mybatis默认采⽤的事务管理器是JDBC,默认是不提交的,需要⼿动提交.)
sqlSession.commit();
// 6. 关闭资源(Only close won't submit)
sqlSession.close();
} }

注意1:默认采⽤的事务管理器是:JDBC.JDBC事务默认是不提交的,需要⼿动提交.

  • 步骤6:运⾏程序,查看运⾏结果,As well as the data in a database table

2.3 MyBatisThe core configuration file name and path

  • 核⼼配置⽂A name is optional,Because of the following code:
// ⽂A name is appear in the program,⽂If a name change,对应这⾥的javaThe program is also changed⼀下就⾏了.
InputStream is = Thread.currentThread().getContextClassLoader().getResource
AsStream("mybatis-config.xml");
  • 核⼼配置⽂A doesn't have to be inresources下!也可以放到D盘根⽬录下!

将mybatis-config.xml⽂件拷⻉⼀份放到D盘根下,然后修改程序:

 // 2. 创建SqlSessionFactory对象
// 这只是⼀个输⼊流,可以⾃⼰new.
InputStream is = new FileInputStream("D:/mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.bui
ld(is);

结论:

  • mybatis核⼼配置⽂A name is optional,Storage path is optional.
  • mybatis核⼼配置⽂A name is not constant,But usually it should⽂A name is called:mybatis-config.xml
  • mybatis核⼼配置⽂A path is not fixed,But usually it should⽂A will be deposited to the class path,This allows items⽬The transplantation of more robust.
  • 在mybatis中提供了⼀个类:Resources【org.apache.ibatis.io.Resources】,This class can from the classpath when
    中获取资源,我们通常使⽤It comes to get lost⼊流InputStream,代码如下:
// 这种⽅Type can only access to resources from the classpath,也就是说mybatis-config.xml⽂A need in the classpath.
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

2.5 MyBatis第⼀A more complete code written

package com.jm.test;
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 org.junit.Test;
import java.io.IOException;
public class MyTest {

@Test
public void testInsert(){

SqlSession sqlSession=null;
try {

//1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//2.创建sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
//3.创建sqlSession对象
sqlSession = sqlSessionFactory.openSession();
//4.执行sql
int count=sqlSession.insert("insertCar");
System.out.println("Update on the number of records="+count);
//5.提交
sqlSession.commit();
} catch (IOException e) {

//6.回滚
if(sqlSession!=null){

sqlSession.rollback();
}
e.printStackTrace();
}finally {

//7.关闭
sqlSession.close();
}
}
}

2.5 引入JUnit

  • JUnit是专⻔Do the unit test components.
    • 在实际开发中,单元测试⼀Usually by usJava程序员来完成的.
    • We want to us⾃⼰written per⼀个业务⽅legally responsible,To ensure that each business⽅The law is in progress⾏Can pass the test 过.
    • In the process of testing involves two concepts:
      • 期望值
      • 实际值
    • Expectations and actual values are the same test to pass,Expectations and the actual value of different unit tests of⾏时会报错.
  • 这⾥引⼊JUnit是为了代替main⽅法.
  • 使⽤JUnit步骤:
    • 第⼀步:引⼊依赖

    •  <!-- junit依赖 -->
      <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
      </dependency>
      
    • 第⼆步:编写单元测试类【测试⽤例】,测试⽤In each case⼀个测试⽅法上使⽤@Test注解进⾏标注.

      • 测试⽤The name of the case and each test⽅The definition of method are specification:
        • 测试⽤Example name:XxxTest
        • 测试⽅legal declaration format:public void test业务⽅法名(){}
        // 测试⽤例
        public class CarMapperTest{
        
        // 测试⽅法
        @Test
        public void testInsert(){
        }
        @Test
        public void testUpdate(){
        }
        }
        
    • 第三步:Can on the class of⾏,也可以在⽅Legally enforced⾏

      • Execute on the class⾏时,All of the tests in this class⽅法都会执⾏.
      • 在⽅Legally enforced⾏时,只执⾏当前的测试⽅法.
  • 编写⼀个测试⽤例,来测试insertCar业务
    CarMapperTest.java
package com.jm.test;
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 org.junit.Test;
import java.io.IOException;
public class MyTest {

@Test
public void testInsert(){

SqlSession sqlSession=null;
try {

//1.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//2.创建sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
//3.创建sqlSession对象
sqlSession = sqlSessionFactory.openSession();
//4.执行sql
int count=sqlSession.insert("insertCar");
System.out.println("Update on the number of records="+count);
//5.提交
sqlSession.commit();
} catch (IOException e) {

//6.回滚
if(sqlSession!=null){

sqlSession.rollback();
}
e.printStackTrace();
}finally {

//7.关闭
sqlSession.close();
}
}
}

2.6 引入日志框架logback

(可参考:Mybatis中文网)

  • 引⼊⽇Chi frame⽬To seemybatis执⾏的具体sql.
  • 启⽤标准⽇志组件,只需要在mybatis-config.xml⽂Pieces to add the following configuration:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>

标准⽇Chi can also⽤,But the configuration flexible enough,Can integrate other⽇志组件,例如:log4j,logback等.

  • logback是⽬前⽇The frame of the volunteers with good performance,较流⾏的,So we choose it.
  • 引⼊logback的步骤:
    • 第⼀步:引⼊logback相关依赖
      <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.11</version>
      <scope>test</scope>
      </dependency>
      
    • 第⼆步:引⼊logback相关配置⽂件(⽂The name of the piece is called logback.xml或logback-test.xml,In the class path)
      <?xml version="1.0" encoding="UTF-8"?>
      <configuration debug="false">
      <!--定义⽇志⽂A memory address-->
      <property name="LOG_HOME" value="/home"/>
      <!-- 控制台输出 -->
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncode r">
      <!--格式化输出:%d表示⽇期,%thread表示线程名,%-5level:级别从左显示5 个字符宽度%msg:⽇志消息,%n是换⾏符-->
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logge
      r{50} - %msg%n</pattern>
      </encoder>
      </appender>
      <!-- 按照每天⽣成⽇志⽂件 -->
      <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAp pender">
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRolling Policy">
      <!--⽇志⽂file output⽂件名-->
      <FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</F ileNamePattern>
      <!--⽇志⽂The number of days to keep the item-->
      <MaxHistory>30</MaxHistory>
      </rollingPolicy>
      <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncode r">
      <!--格式化输出:%d表示⽇期,%thread表示线程名,%-5level:级别从左显示5 个字符宽度%msg:⽇志消息,%n是换⾏符-->
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logge
      r{50} - %msg%n</pattern>
      </encoder>
      <!--⽇志⽂件最⼤的⼤⼩-->
      <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTrig geringPolicy">
      <MaxFileSize>100MB</MaxFileSize>
      </triggeringPolicy>
      </appender>
      <!--mybatis log configure-->
      <logger name="com.apache.ibatis" level="TRACE"/>
      <logger name="java.sql.Connection" level="DEBUG"/>
      <logger name="java.sql.Statement" level="DEBUG"/>
      <logger name="java.sql.PreparedStatement" level="DEBUG"/>
      <!-- ⽇志输出级别,logback⽇Ambition level including five:TRACE < DEBUG < INFO < WARN < ER ROR -->
      <root level="DEBUG">
      <appender-ref ref="STDOUT"/>
      <appender-ref ref="FILE"/>
      </root>
      </configuration>
      
    • 第三步:再次执⾏单元测试⽅法testInsertCar,Check to see if the console issql语句输出

2.7 MyBatis的封装工具类SqlSessionUtil

  • 每⼀次获取SqlSessionObject code too complicated,封装⼀个⼯具类

SqlSessionUtil.java Java

package com.jm.unit;
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;
/** * mybatiss工具类 */
public class SqlSessionUtil {

//To prevent the object is created
private SqlSessionUtil(){
}
//一个数据库对应一个SqlSessionFactory对象
private static SqlSessionFactory sqlSessionFactory;
//类加载时初始化sqlSessionFactory对象
static {

try {

sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {

throw new RuntimeException(e);
}
}
//每调⽤⼀次openSession()可获取⼀个新的会话,该会话⽀持⾃动提交.
public static SqlSession openSession(){

return sqlSessionFactory.openSession();
}
}
  • 测试⼯具类,将testInsertCar()改造
 @Test
public void testInsert2(){

SqlSession sqlSession = SqlSessionUtil.openSession();
int count = sqlSession.insert("insertCar");
System.out.println("插入条数="+count);
sqlSession.close();
}

三.使⽤MyBatis完成CRUD

  • 准备工作
    • 创建module(Maven的普通Java模块):mybatis-002-crud
    • pom.xml
      • 打包⽅式jar
      • 依赖:mybatis依赖
        • mysql驱动依赖
        • junit依赖
        • logback依赖
      • mybatis-config.xmlUnder the root of a class
      • CarMapper.xmlUnder the root of a class
      • logback.xmlUnder the root of a class
      • 提供com.powernode.mybatis.utils.SqlSessionUtil⼯具类
      • 创建测试⽤例:com.powernode.mybatis.CarMapperTest

3.1 insert(Create)

  • 在MyBatis中可以这样做:
    • 在Java程序中,将数据放到Map集合中
    • 在sql语句中使⽤ #{map集合的key} to complete the value transfer,#{} 等同于JDBC中的 ? ,#{}就是占位符

Java程序

package com.powernode.mybatis;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/** * 测试MyBatis的CRUD */
public class CarMapperTest {

@Test
public void testInsertCar(){

// 准备数据
Map<String, Object> map = new HashMap<>();
map.put("k1", "103");
map.put("k2", "奔驰E300L");
map.put("k3", 50.3);
map.put("k4", "2020-10-01");
map.put("k5", "燃油⻋");
// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执⾏SQL语句(使⽤map集合给sqlTransfer data statement)
int count = sqlSession.insert("insertCar", map);
System.out.println("插⼊了⼏条记录:" + count);
} }

SQL语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace先随便写-->
<mapper namespace="car">
<insert id="insertCar">
insert into t_car(car_num,brand,guide_price,produce_time,car_typ
e) values(#{k1},#{k2},#{k3},#{k4},#{k5})
</insert>
</mapper>

注意1:#{} 的⾥⾯必须填写map集合的key,不能随便写.

  • 如果#{}⾥写的是mapThe collection does not existkey会有什么问题?
    • 正常执⾏.不过 #{kk} 的写法导致⽆法获取到map集合中的数据,最终 Lead to a database tablecar_num插⼊了NULL

在以上sql语句中,可以看到#{k1} #{k2} #{k3} #{k4} #{k5}的可读性太差,为了增强可读性.

JavaA program to do the following modification:

Map<String, Object> map = new HashMap<>();
// 让keyThe readability of the enhance
map.put("carNum", "103");
map.put("brand", "奔驰E300L");
map.put("guidePrice", 50.3);
map.put("produceTime", "2020-10-01");
map.put("carType", "燃油⻋");

SQL语句做如下修改,It can enhance the program readability:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car">
<insert id="insertCar">
insert into t_car(car_num,brand,guide_price,produce_time,car_type)
values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>
</mapper>

使⽤MapCollections can be passed arguments,那使⽤pojo(简单普通的java对象)Can complete the reference?测试⼀下:

  • 第⼀步:定义⼀个pojo类Car,Provide relevant properties.
package com.jm.pojo;
/** * 封装Car类 */
public class Car {

private Long id;
private String carNum;
private String brand;
private Double guidePrice;
private String produceTime;
private String carType;
@Override
public String toString() {

return "Car{" +
"id=" + id +
", carNum='" + carNum + '\'' +
", brand='" + brand + '\'' +
", guidePrice=" + guidePrice +
", produceTime='" + produceTime + '\'' +
", carType='" + carType + '\'' +
'}';
}
public Long getId() {

return id;
}
public void setId(Long id) {

this.id = id;
}
public String getCarNum() {

return carNum;
}
public void setCarNum(String carNum) {

this.carNum = carNum;
}
public String getBrand() {

return brand;
}
public void setBrand(String brand) {

this.brand = brand;
}
public Double getGuidePrice() {

return guidePrice;
}
public void setGuidePrice(Double guidePrice) {

this.guidePrice = guidePrice;
}
public String getProduceTime() {

return produceTime;
}
public void setProduceTime(String produceTime) {

this.produceTime = produceTime;
}
public String getCarType() {

return carType;
}
public void setCarType(String carType) {

this.carType = carType;
}
public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {

this.id = id;
this.carNum = carNum;
this.brand = brand;
this.guidePrice = guidePrice;
this.produceTime = produceTime;
this.carType = carType;
}
public Car() {

}
}
  • 第⼆步:Java程序
 @Test
public void testInsertCar(){

SqlSession sqlSession = SqlSessionUtil.openSession();
//封装数据
Car car=new Car(null,"333","法拉利",400.0,"2008-4-15","燃油车");
int count=sqlSession.insert("insertCar",car);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
  • 第三步:SQL语句
 <insert id="insertCar">
insert into t_car (id, car_num, brand, guide_price, produce_time, car_type)
values (null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType});
</insert>

总结:

  • 如果采⽤map集合传参,#{} ⾥写的是map集合的key,如果key不存在不会报错,Database will be inserted in the table ⼊NULL.
  • 如果采⽤POJO传参,#{} ⾥写的是get⽅法的⽅The legal name is removedgetAfter the rest of the word⾸字⺟变⼩写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get⽅Law does not exist, an.

注意:When actually pass parameters have⼀个属性parameterType,这个属性⽤To specify the parameter data type,But this genus Sex can be omitted

<insert id="insertCar" parameterType="java.util.Map">
insert into t_car(car_num,brand,guide_price,produce_time,car_type) values
(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert> <insert id="insertCarByPOJO" parameterType="com.powernode.mybatis.pojo.Car" >
insert into t_car(car_num,brand,guide_price,produce_time,car_type) values
(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>

3.2 delete(Delete)

需求:根据car_num进⾏删除.

SQL语句这样写:

<delete id="deleteByCarNum">
delete from t_car where car_num = #{SuiBianXie}
</delete>

Java程序这样写:

@Test
public void testDeleteByCarNum(){

// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执⾏SQL语句
int count = sqlSession.delete("deleteByCarNum", "102");
System.out.println("删除了⼏条记录:" + count);
}

注意:When a placeholder only⼀个的时候,${} ⾥⾯Feel free to write the content of the.

3.3 update(Update)

需求:修改id=34的Car信息,car_num为102,brand为⽐亚迪汉,guide_price为30.23,produce_time 为2018-09-10,car_type为电⻋

SQL语句如下:

<update id="updateCarByPOJO">
update t_car set
car_num = #{carNum}, brand = #{brand},
guide_price = #{guidePrice}, produce_time = #{produceTime},
car_type = #{carType}
where id = #{id}
</update>

Java代码如下:

 @Test
public void testUpdateCarByPOJO(){

// 准备数据
Car car = new Car();
car.setId(34L);
car.setCarNum("102");
car.setBrand("⽐亚迪汉");
car.setGuidePrice(30.23);
car.setProduceTime("2018-09-10");
car.setCarType("电⻋");
// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执⾏SQL语句
int count = sqlSession.update("updateCarByPOJO", car);
System.out.println("更新了⼏条记录:" + count);
}

3.4 select(Retrieve)

selectStatements and other statements:Inquiries will be⼀个结果集.
查询⼀条数据
需求:查询id为1的Car信息

SQL语句如下:

<select id="selectCarById">
select * from t_car where id = #{id}
</select>

Java程序如下:

@Test
public void testSelectCarById(){

// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执⾏SQL语句
Object car = sqlSession.selectOne("selectCarById", 1);
System.out.println(car);
}

According to the above methods will be abnormal,原因是什么呢?

### Error querying database. Cause: org.apache.ibatis.executor.ExecutorExc
eption:
A query was run and no Result Maps were found for the Mapped Statement
'car.selectCarById'.
【翻译】:对于⼀A query is,Didn't find the results of the query mapping.
It's likely that neither a Result Type nor a Result Map was specified.
【翻译】:很可能既没有指定结果类型,也没有指定结果映射.

以上的异常⼤To mean:对于⼀A query is,You need to specify it“结果类型”或者“结果映射”.
所以说,你想让mybatis查询之后返回⼀个Java对象的话,⾄Less you have to tellmybatis返回⼀个什么类型的 Java对象,可以在标签中添加resultType属性,⽤To specify the type of query to convert:

<select id="selectCarById" resultType="com.powernode.mybatis.pojo.Car">
select * from t_car where id = #{id}
</select>

But it is strange that the returnedCar对象,只有id和brandTwo attributes values,The values of other attributes arenull,这是为什么呢?
我们尝试在sql语句中使⽤asKey word to query the results of the column names to try:

<select id="selectCarById" resultType="com.powernode.mybatis.pojo.Car">
select
id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType
from
t_car
where
id = #{id}
</select>

通过测试得知,If when the query results of the field name andjavaCorresponding attributes of a class name is not on,可以采⽤as关键字起别名, Of course there are other solution⽅案,我们后⾯再看.

查询多条数据

需求:查询所有的Car信息.

SQL语句如下:

<!--虽然结果是List集合,但是resultTypeAttributes you need to specify is thatList集合中元素的类型.-->
<select id="selectCarAll" resultType="com.powernode.mybatis.pojo.Car">
<!--记得使⽤as起别名,To make the query results field name andjavaAttributes of a class name on the corresponding.-->
select
id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType
from
t_car
</select>

Java代码如下:

@Test
public void testSelectCarAll(){

// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执⾏SQL语句
List<Object> cars = sqlSession.selectList("selectCarAll");
// 输出结果
cars.forEach(car -> System.out.println(car));
}

3.5 关于SQL Mapper的namespace

在SQL Mapper配置⽂label in the filenamespaceAttributes can be translated into a namespace,This namespace is mainly in order to prevent⽌sqlId冲突的.
创建CarMapper2.xml⽂件,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car2">
<select id="selectCarAll" resultType="com.powernode.mybatis.pojo.Car">
select
id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType
from
t_car
</select>
</mapper>

不难看出,CarMapper.xml和CarMapper2.xml⽂all in the item id=“selectCarAll”
将CarMapper2.xml配置到mybatis-config.xml⽂件中.

<mappers>
<mapper resource="CarMapper.xml"/>
<mapper resource="CarMapper2.xml"/>
</mappers>

编写Java代码如下:

@Test
public void testNamespace(){

// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执⾏SQL语句
List<Object> cars = sqlSession.selectList("selectCarAll");
// 输出结果
cars.forEach(car -> System.out.println(car)); }

运行结果:

org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.IllegalArgumentException:
selectCarAll is ambiguous in Mapped Statements collection (try using the
full name including the namespace, or rename one of the entries)
【翻译】selectCarAll在Mapped StatementsThe collection is not clear(请尝试使⽤Namespace contains all 名,Or rename them⼀个条⽬)
【⼤To the meaning is】selectCarAll重名了,Either you are thereselectCarAll前添加⼀个名称空间,I want you to change other names.

Java代码修改如下:

@Test
public void testNamespace(){

// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执⾏SQL语句
//List<Object> cars = sqlSession.selectList("car.selectCarAll");
List<Object> cars = sqlSession.selectList("car2.selectCarAll");
// 输出结果
cars.forEach(car -> System.out.println(car));
}

四、MyBatis核心配置文件详解

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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/po wernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="CarMapper.xml"/>
<mapper resource="CarMapper2.xml"/>
</mappers>
</configuration>
  • configuration:根标签,表示配置信息.
  • environments:环境(多个),以“s”结尾表示复数,也就是说mybatisCan configure the environment of multiple data sources
    • default属性:Indicates the default use⽤Which is the environment,default后⾯填写的是environment的id.default The value of only need andenvironment的id值⼀致即可.
  • environment:具体的环境配置(主要包括:事务管理器的配置 + 数据源的配置
    • id:to the current environment⼀个唯⼀标识,该标识⽤在environments的default后⾯,⽤To specify a default environment selection
  • transactionManager:配置事务管理器
    • type属性:Specify the transaction manager make specific⽤什么⽅式,Optional values include two
      • JDBC:使⽤JDBC原⽣的事务管理机制.底层原理:事务开启 conn.setAutoCommit(false); …处理业务…事务提交conn.commit();
      • MANAGED:To manage affairs to other containers,⽐如WebLogic、JBOSS等.If there is no regulatory affairs 容器,则没有事务.The meaning of no transaction:只要执⾏⼀条DML语句,则提交⼀次.
  • dataSource:指定数据源
    • type属性:⽤To specify the specific make⽤The strategy of database connection pool,Optional value includes three
      • UNPOOLED:采⽤传统的获取连接的⽅式,虽然也实现Javax.sql.DataSourc接⼝,但 是 并没有使⽤池的思想.+
        • property可以是:
          • driver 这是 JDBC 驱动的 Java 类全限定名.
          • url 这是数据库的 JDBC URL 地址.
          • username 登录数据库的⽤户名.
          • password 登录数据库的密码.
          • defaultTransactionIsolationLevel 默认的连接事务隔离级别.
          • defaultNetworkTimeout Waiting for the default database operation to complete⽹络超时时间(单位:毫秒)
      • POOLED:采⽤传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实 现.
        • property可以是(除了包含UNPOOLED中之外):
          • poolMaximumActiveConnections 在任意时间可存在的活动(正在使⽤)连接数量,默认值:10
          • poolMaximumIdleConnections 任意时间可能存在的空闲连接数.
          • 其它…
      • JNDI:采⽤服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到 DataSource是不⼀样.如果不是web或者maven的war⼯程,JNDI是不能使⽤的.
        • property可以是(Most contains only the following two properties):
          • initial_context 这个属性⽤来在 InitialContext Look up and down⽂(即, initialContext.lookup(initial_context))这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性.
          • data_source This is cited⽤Data source instance position up and down⽂路径.提供了 initial_context will be configured In its back up and down⽂中进⾏查找,没有提供时则直接在 InitialContext 中查找.
  • mappers:在mappers标签中可以配置多个sql映射⽂件的路径.
  • mapper:配置某个sql映射⽂件的路径
    • resource属性:使⽤相对于类路径的资源引⽤⽅式
    • url属性:使⽤完全限定资源定位符(URL)⽅式

4.1 environment

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">
<configuration>
<!--默认使⽤开发环境-->
<!--<environments default="dev">-->
<!--默认使⽤⽣产环境-->
<environments default="production">
<!--开发环境-->
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/po wernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<!--⽣产环境-->
<environment id="production">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/my batis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>

CarMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car">
<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>
</mapper>

ConfigurationTest.testEnvironment


package com.powernode.mybatis;
import com.powernode.mybatis.pojo.Car;
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 org.junit.Test;
public class ConfigurationTest {

@Test
public void testEnvironment() throws Exception {

// 准备数据
Car car = new Car();
car.setCarNum("133");
car.setBrand("丰⽥霸道");
car.setGuidePrice(50.3);
car.setProduceTime("2020-01-10");
car.setCarType("燃油⻋");
// ⼀个数据库对应⼀个SqlSessionFactory对象
// Two corresponding databaseSqlSessionFactory对象,以此类推
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSession
FactoryBuilder();
// 使⽤默认数据库
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession(true);
int count = sqlSession.insert("insertCar", car);
System.out.println("插⼊了⼏条记录:" + count);
// 使⽤指定数据库
SqlSessionFactory sqlSessionFactory1 = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "dev");
SqlSession sqlSession1 = sqlSessionFactory1.openSession(true);
int count1 = sqlSession1.insert("insertCar", car);
System.out.println("插⼊了⼏条记录:" + count1);
}
}

4.2 transactionManager

mybatis-config2.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">
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="MANAGED"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>

ConfigurationTest.testTransactionManager


@Test
public void testTransactionManager()throws Exception{

// 准备数据
Car car=new Car();
car.setCarNum("133");
car.setBrand("丰⽥霸道");
car.setGuidePrice(50.3);
car.setProduceTime("2020-01-10");
car.setCarType("燃油⻋");
// 获取SqlSessionFactory对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFact
oryBuilder();
SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBuilder.build(R
esources.getResourceAsStream("mybatis-config2.xml"));
// 获取SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
// 执⾏SQL
int count=sqlSession.insert("insertCar",car);
System.out.println("插⼊了⼏条记录:"+count);
}

When the transaction manager is:JDBC

  • 采⽤JDBC的原⽣事务机制:
    • 开启事务:conn.setAutoCommit(false);
    • 处理业务…
    • 提交事务:conn.commit();

When the transaction manager is:MANAGED

  • To the container to manage affairs,但⽬前使⽤Local program,No container⽀持,当mybatisCan't find the container⽀持时:没有事务.That is to say as long as hold⾏⼀条DML语句,则提交⼀次.

4.3 dataSource

mybatis-config3.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">
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<!--以使⽤第三⽅Connection pool connection⼝-->
<dataSource type="JNDI">
<!--使⽤数据库 连接池.【这个连接池是mybatis⾃⼰实现的.】-->
<dataSource type="POOLED">
<!--不会使⽤连接池,每⼀will be newly builtJDBC连接对象-->
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>

ConfigurationTest.testDataSource

 @Test
public void testDataSource()throws Exception{

// 准备数据
Car car=new Car();
car.setCarNum("133");
car.setBrand("丰⽥霸道");
car.setGuidePrice(50.3);
car.setProduceTime("2020-01-10");
car.setCarType("燃油⻋");
// 获取SqlSessionFactory对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFact
oryBuilder();
SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBuilder.build(R
esources.getResourceAsStream("mybatis-config3.xml"));
// 获取SqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession(true);
// 执⾏SQL
int count=sqlSession.insert("insertCar",car);
System.out.println("插⼊了⼏条记录:"+count);
// 关闭会话
sqlSession.close();
}

结论

  • UNPOOLED不会使⽤连接池,每⼀will be newly builtJDBC连接对象.
  • POOLED会使⽤数据库 连接池.【这个连接池是mybatis⾃⼰实现的.】
  • JNDI表示对接JNDIThe server connection pool.这种⽅Type to the we can make⽤第三⽅Connection pool connection⼝.如果 想使⽤dbcp、c3p0、druid(德鲁伊)等,需要使⽤这种⽅式.

type="POOLED"的时候,它的属性有哪些?

<?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">
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<!--最⼤连接数-->
<property name="poolMaximumActiveConnections" value="3"/>
<!--Most free number-->
<property name="poolMaximumIdleConnections" value="1"/>
<!--强⾏Return to the pool-->
<property name="poolMaximumCheckoutTime" value="20000"/>
<!--这是⼀a low-level setting,If get connection spent quite a⻓的时间,The connection pool will print form 态⽇Ambition and try to get⼀个连接(To avoid in the case of a configuration error⼀Straight failure and do not print⽇志),默认值:20000毫秒(即 20 秒).-->
<property name="poolTimeToWait" value="20000"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>
  • poolMaximumActiveConnections:最⼤The activities of the number of connections.默认值10
  • poolMaximumIdleConnections:最⼤The number of idle connections.默认值5
  • poolMaximumCheckoutTime:强⾏Return to the pool.默认值20秒.
  • poolTimeToWait:当⽆Method to get to the free connection,每隔20秒打印⼀次⽇志(时⻓是可以配置的)
  • 当然,还有其他属性.对于连接池来说,以上⼏个属性⽐较重要.
  • 最⼤The activities of the number of connections is connection pool connection number of ceiling.默认值10,如果有10A request is made⽤这10个连接, 第11A request can only wait for the free connection.
  • 最⼤The number of idle connections.默认值5,How to have5个空闲连接,当第6A connection to free up,The connection pool will choose to close the connection object.To reduce the overhead of database.
  • Need according to the system of concurrent situation,To reasonably adjust the connection pool is the most⼤The number of connections as well as the most number of free.Give full play to the database connection pool 性能.【Can according to the actual situation in⾏测试,然后调整⼀A reasonable number of.】

在这里插入图片描述

4.4 properties

mybatis提供了更加灵活的配置,Connect to the database information can be written separately⼀个属性资源⽂件中,We assume that the class to the root of the road Created belowjdbc.properties⽂件,配置如下:
jdbc.properties Properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/powernode

在mybatis核⼼配置⽂件中引⼊并使⽤:
mybatis-config4.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">
<configuration>
<!--引⼊External property resources⽂件-->
<properties resource="jdbc.properties">
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="root"/>
</properties>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--${key}使⽤-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>

编写Java程序进⾏测试:
ConfigurationTest.testProperties

 @Test
public void testProperties()throws Exception{

SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFacto
ryBuilder();
SqlSessionFactory sqlSessionFactory=sqlSessionFactoryBuilder.build(Re
sources.getResourceAsStream("mybatis-config4.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession();
Object car=sqlSession.selectOne("selectCarByCarNum");
System.out.println(car);
}

properties两个属性:

  • resource:This attribute from the root class start loading.【常⽤的.】
  • url:从指定的url加载,假设⽂件放在d:/jdbc.properties,这个url可以写成:file:///d:/jdbc.properties.Pay attention to is the three slashes oh.

注意:如果不知道mybatis-config.xml⽂A label to write in order,可以有两种⽅The order type to know it:

  • 第⼀种⽅式:查看dtd约束⽂件.
  • 第⼆种⽅式:通过ideaAn error message.【⼀般采⽤这种⽅式】

4.5 mapper

mapper标签⽤来指定SQL映射⽂件的路径,Contains a variety of specified⽅式,这⾥Mainly to see two of these:
第⼀种:resource,From the root class start loading【⽐url常⽤】
mybatis-config4.xml

<mappers>
<mapper resource="CarMapper.xml"/>
</mappers>

如果是这样写的话,Must ensure that the class under the root of theCarMapper.xml⽂件. If a class is under the root of⼀A package is called test,CarMapper.xml如果放在test包下的话,This configuration should be like this:
mybatis-config4.xml

<mappers>
<mapper resource="test/CarMapper.xml"/>
</mappers>

第⼆种:url,从指定的urlLocation loaded
假设CarMapper.xml⽂件放在d盘的根下,This configuration will need to write:
mybatis-config4.xml

<mappers>
<mapper url="file:///d:/CarMapper.xml"/>
</mappers>

五.在WEB中应用MyBatis(使用MVC架构模式)

5.1 准备数据库表t_act

drop table if exists t_act;
create table t_act(
id int primary key auto_increment,
actno varchar(255),
balance decimal
);
INSERT INTO `t_act` (`id`, `actno`, `balance`) VALUES (1, 'act001', 50000.0);
INSERT INTO `t_act` (`id`, `actno`, `balance`) VALUES (2, 'act002', 0);

5.2 实现步骤

第一步:搭建环境,导入依赖

第二步:前端页面index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>银行账户转账</title>
</head>
<body>
<form action="/bank/transfer" method="post">
转出账号:<input type="text" name="fromActno"><br>
转入账号:<input type="text" name="toActno"><br>
转账金额:<input type="text" name="money"><br>
<input type="submit" value="转账">
</form>
</body>
</html>

第三步:创建包

  • com.powernode.bank.pojo
  • com.powernode.bank.dao
  • com.powernode.bank.dao.impl
  • com.powernode.bank.service
  • com.powernode.bank.service.impl
  • com.powernode.bank.web
  • com.powernode.bank.exception
  • com.powernode.bank.utils:将之前编写的SqlSessionUtil⼯Class copy⻉to the package.

第四步:定义pojo类:Account

package com.jm.bank.pojo;
/** * 账户类,封装数据 */
public class Account {

private Long id;
private String actno;
private Double balance;
@Override
public String toString() {

return "Account{" +
"id=" + id +
", actno='" + actno + '\'' +
", balance=" + balance +
'}';
}
public Long getId() {

return id;
}
public void setId(Long id) {

this.id = id;
}
public String getActno() {

return actno;
}
public void setActno(String actno) {

this.actno = actno;
}
public Double getBalance() {

return balance;
}
public void setBalance(Double balance) {

this.balance = balance;
}
public Account(Long id, String actno, Double balance) {

this.id = id;
this.actno = actno;
this.balance = balance;
}
public Account() {

}
}

第五步:编写AccountDao接口,以及AccountDaoImpl实现类

AccountDao(接口)

package com.jm.bank.dao;
import com.jm.bank.pojo.Account;
public interface AccountDao {

Account selectByActno(String actno);
int updateByActno(Account account);
}

TransferDaoImpl(实现类)

package com.jm.bank.dao.impl;
import com.jm.bank.dao.AccountDao;
import com.jm.bank.pojo.Account;
import com.jm.bank.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
public class TransferDaoImpl implements AccountDao {

@Override
public Account selectByActno(String actno) {

SqlSession sqlSession = SqlSessionUtil.openSession();
Account account=sqlSession.selectOne("selectByActno",actno);
return account;
}
@Override
public int updateByActno(Account account) {

SqlSession sqlSession = SqlSessionUtil.openSession();
int count=sqlSession.update("updateByActno",account);
return count;
}
}

第六步:编写SQL映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="account">
<select id="selectByActno" resultType="com.jm.bank.pojo.Account">
select *
from t_act
where actno=#{actno};
</select>
<update id="updateByActno">
update t_act
set balance=#{balance}
where actno=#{actno};
</update>
</mapper>

第七步:编写AccountService接口以及AccountServiceImpl

AccountService(接口)

package com.jm.bank.service;
import com.jm.bank.exception.MoneyNotEnoughException;
import com.jm.bank.exception.TransferException;
public interface AccountService {

void transfer(String fromActno,String toActno,double money) throws MoneyNotEnoughException, TransferException;
}

TransferServiceImpl(实现类)

package com.jm.bank.service.impl;
import com.jm.bank.dao.AccountDao;
import com.jm.bank.dao.impl.TransferDaoImpl;
import com.jm.bank.exception.MoneyNotEnoughException;
import com.jm.bank.exception.TransferException;
import com.jm.bank.pojo.Account;
import com.jm.bank.service.AccountService;
public class TransferServiceImpl implements AccountService {

AccountDao accountDao=new TransferDaoImpl();
@Override
public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, TransferException {

Account fromAct = accountDao.selectByActno(fromActno);
Account toAct = accountDao.selectByActno(toActno);
//1.Judgment is transfer amount a enough,Not enough to throw exceptions
if(fromAct.getBalance()<money){

throw new MoneyNotEnoughException("对不起,余额不足,无法转账!");
}
//2.Update user's amount after transfer
//To update the data in the memory
fromAct.setBalance(fromAct.getBalance()-money);
toAct.setBalance(toAct.getBalance()+money);
//To update the data in the database
int count=accountDao.updateByActno(fromAct);
count+=accountDao.updateByActno(toAct);
if(count!=2){

throw new TransferException("转账异常,未知原因!");
}
}
}

第⼋步:编写AccountServlet

package com.jm.bank.web;
import com.jm.bank.exception.MoneyNotEnoughException;
import com.jm.bank.exception.TransferException;
import com.jm.bank.service.AccountService;
import com.jm.bank.service.impl.TransferServiceImpl;
import com.jm.bank.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/transfer")
public class TransferServlet extends HttpServlet {

AccountService accountService=new TransferServiceImpl();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

//添加事务代码
SqlSession sqlSession = SqlSessionUtil.openSession();
//获取表单数据
String fromActno = request.getParameter("fromActno");
String toActno = request.getParameter("toActno");
double money = Double.parseDouble(request.getParameter("money"));
try {

//调用业务逻辑层方法,进行操作
accountService.transfer(fromActno,toActno,money);
//Here said the transfer success
//调用view展示结果
response.sendRedirect(request.getContextPath()+"/success.html");
} catch (MoneyNotEnoughException e) {

response.sendRedirect(request.getContextPath()+"/error1.html");
} catch (TransferException e) {

response.sendRedirect(request.getContextPath()+"/error2.html");
}
//提交事务
sqlSession.commit();
//关闭事务
SqlSessionUtil.close(sqlSession);
}
}

5.3 MyBatis对象作用域

5.3.1 SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了. 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量). 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情.

5.3.2 SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例. 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”.因此 SqlSessionFactory 的最佳作用域是应用作用域. 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式.

5.3.3 SqlSession

每个线程都应该有它自己的 SqlSession 实例.SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域. 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行. 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession. 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中. 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它. 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中.

5.4 事务问题

为了保证service和dao中使⽤的SqlSession对象是同⼀个,可以将SqlSession对象存放到ThreadLocal当中.修改SqlSessionUtil⼯具类:

package com.jm.bank.util;
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;
/** * mybatiss工具类 */
public class SqlSessionUtil {

private SqlSessionUtil(){
}
private static SqlSessionFactory sqlSessionFactory;
/** * 类加载时初始化sqlSessionFactory对象 */
static {

try {

sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {

throw new RuntimeException(e);
}
}
//全局的,Definition of a server can be a
private static ThreadLocal<SqlSession> local=new ThreadLocal<>();
/** * 每调⽤⼀次openSession()可获取⼀个新的会话,该会话⽀持⾃动提交. * * @return A new session object */
public static SqlSession openSession(){

SqlSession sqlSession = local.get();
if(sqlSession==null){

sqlSession=sqlSessionFactory.openSession();
local.set(sqlSession);
}
return sqlSession;
}
/** * 关闭SqlSession对象 * @param sqlSession */
public static void close(SqlSession sqlSession){

if(sqlSession!=null){

sqlSession.close();
local.remove();
}
}
}

5.5 Analyzing the problems existing in the application

package com.jm.bank.dao.impl;
import com.jm.bank.dao.AccountDao;
import com.jm.bank.pojo.Account;
import com.jm.bank.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
public class TransferDaoImpl implements AccountDao {

@Override
public Account selectByActno(String actno) {

SqlSession sqlSession = SqlSessionUtil.openSession();
Account account=sqlSession.selectOne("selectByActno",actno);
return account;
}
@Override
public int updateByActno(Account account) {

SqlSession sqlSession = SqlSessionUtil.openSession();
int count=sqlSession.update("updateByActno",account);
return count;
}
}

不难发现,这个dao实现类中的⽅Method code is fixed,基本上就是⼀⾏代码,通过SqlSession对象调⽤ insert、delete、update、select等⽅法,这个类中的⽅No business logic,既然是这样,This class can we dynamic⽣成,Later can don't write this class?
答案:可以.

六.MyBatisThe interface agent mechanism and use

直接调⽤The following code can be obtaindao接⼝的代理类,mybatis内部已经实现了.

AccountDao accountDao = (AccountDao)sqlSession.getMapper(AccountDao.class);

使⽤The code above is the premise of:AccountMapper.xml⽂件中的namespace必须和dao接⼝的全限定名称⼀致,id必须和dao接⼝中⽅法名⼀致.

七.MyBatis小技巧

7.1 #{}和${}

#{}:先编译sql语句,再给占位符传值,底层是PreparedStatement实现.可以防⽌sql注⼊,⽐较常⽤.

${}:先进⾏sql语句拼接,然后再编译sql语句,底层是Statement实现.存在sql注⼊现象.只有在需要 进⾏sqlStatements keyword stitching will⽤到.

7.1.1 什么情况下必须使用${}

当需要进⾏sqlStatement keywords together.必须使⽤${}
需求:通过向sqlNote in the sentence⼊asc或desc关键字,To complete the data in ascending or descending order.
order by carNum #{key}

7.1.2 拼接表名

使⽤#{}会是这样:select * from ‘t_car’
使⽤${}会是这样:select * from t_car

7.1.3 批量删除

使⽤#{} :delete from t_user where id in(‘1,2,3’) 执⾏错误:1292 - Truncated incorrect DOUBLE value: ‘1,2,3’
使⽤${} :delete from t_user where id in(1, 2, 3)

7.1.4 模糊查询

使⽤${}
brand like ‘%${brand}%’

使⽤#{}
第⼀种:concat函数
brand like concat(‘%’,#{brand},‘%’)
第⼆种:双引号⽅式
brand like “%”#{brand}“%”

7.2 typeAliases 起别名

在mybatis-config.xml⽂件中使⽤typeAliasesTags to names,包括两种⽅式:
第⼀种⽅式:typeAlias

<typeAliases>
<typeAlias type="com.powernode.mybatis.pojo.Car" alias="Car"/>
</typeAliases>
  • ⾸先要注意typeAliases标签的放置位置,如果不清楚的话,Can see the error message.
  • typeAliases标签中的typeAlias可以写多个.
  • typeAlias:
    • type属性:Assigned to which class names
    • alias属性:别名.
      • alias属性不是必须的,如果缺省的话,typeAttribute specifies the type of the name of the class name as Jane alias.
      • alias是⼤⼩写不敏感的.也就是说假设alias=“Car”,再⽤的时候,可以CAR,也可以car, 也可以Car,都⾏.

第⼆种⽅式:package
如果⼀A package of class too much,Every class names,会导致typeAliasThe tag is more,所以mybatis⽤提供 package的配置⽅式,只需要指定包名,The package of all classes⾃Activate the alias,Alias is the name of the class Jane.And aliases don't 区分⼤⼩写.

<typeAliases>
<package name="com.powernode.mybatis.pojo"/>
</typeAliases>

packageAlso can configure multiple.

在SQL映射⽂件中⽤⼀下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mybatis.mapper.CarMapper">
<select id="selectAll" resultType="CAR">
select
id,car_num as carNum,brand,guide_price as guidePrice,produce_t
ime as produceTime,car_type as carType
from
t_car
order by carNum ${key}
</select>
<select id="selectByCarType" resultType="car">
select
id,car_num as carNum,brand,guide_price as guidePrice,produce_t
ime as produceTime,car_type as carType
from
t_car
where
car_type = '${carType}'
</select>
</mapper>

7.3 mappers

SQL映射⽂件的配置⽅There are four types of formulas:

  • resource:从类路径中加载
  • url:From the specified resource fully qualified path to load
  • class:使⽤映射器接⼝实现类的完全限定类名
  • package:将包内的映射器接⼝实现全部注册为映射器

7.3.1 resource

这种⽅From the classpath loading configuration⽂件,所以这种⽅式要求SQL映射⽂Pieces must be placedresources⽬record or its sub⽬录下.

<mappers>
<mapper resource="com.jm.mapper.CarMapper.xml"/>
</mappers>

7.3.2 url

这种⽅The formula obviously makes⽤The absolute path⽅式,This configuration is rightSQL映射⽂Does not require a storage locations,随意.

<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>

7.3.3 class

如果使⽤这种⽅The formula must be full⾜以下条件:

  • SQL映射⽂件和mapper接⼝放在同⼀个⽬录下.
  • SQL映射⽂A name must also be andmapper接⼝名⼀致.
<!-- 使⽤映射器接⼝实现类的完全限定类名 -->
<mappers>
<mapper class="com.powernode.mybatis.mapper.CarMapper"/>
</mappers>

7.3.4 package

如果class较多,可以使⽤这种package的⽅式,But the premise condition and the⼀种⽅式⼀样.

<!-- 将包内的映射器接⼝实现全部注册为映射器 -->
<mappers>
<package name="com.jm.mapper"/>
</mappers>

7.4 idea配置文件模板

mybatis-config.xml和SqlMapper.xml⽂Pieces are availableIDEACreate a good template in advance,Later by templates to create the configuration⽂件.
在这里插入图片描述

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">
<configuration>
<!--引入外部文件-->
<properties resource=""></properties>
<!--起别名-->
<typeAliases>
<package name=""/>
</typeAliases>
<!--环境配置-->
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--映射-->
<mappers>
<package name=""/>
</mappers>
</configuration>

SqlMapper.xml模板

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
</mapper>

7.5 When inserting data access to automatically generate the primary key of the

前提是:主键是⾃动⽣成的.

插⼊⼀A new record,⾃动⽣becomes the primary key,⽽The primary key needs to be in other tables to make⽤时.
插⼊⼀个⽤The household data at the same time need to give the⽤户分配⻆⾊:需要将⽣成的⽤户的id插⼊到⻆⾊表的user_id字段上.

第⼀种⽅式:Can be plugged in first⼊⽤户数据,再写⼀A query to obtainid,然后再插⼊user_id字段.【⽐较麻烦】
第⼆种⽅式:mybatis提供了⼀种⽅more convenient.

 <!-- useGeneratedKeys="true" Using automatically generate the primary key keyProperty="id" Specify the primary key value assigned to an object which property,This means that the primary key assigned toCar的id属性 -->
<insert id="insertUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>

八、MyBatis参数处理

8.1 单个简单类型参数

简单类型包括:

  • byte short int long float double char
  • Byte Short Integer Long Float Double Character
  • String
  • java.util.Date
  • java.sql.Date
 <select id="selectById" resultType="Student" parameterType="java.lang.Long">
select * from t_student where id=#{id};
</select>
<select id="selectByName" resultType="Student">
select *
from t_student where name=#{name};
</select>
<select id="selectByBirth" resultType="Student">
select *
from t_student where birth=#{birth};
</select>
<select id="selectBySex" resultType="Student">
select *
from t_student where sex=#{sex};
</select>

补充:sql语句中的javaType,jdbcType,以及select标签中的parameterType属性,都是⽤来帮助 mybatis进⾏类型确定的.

  • javaType:可以省略
  • jdbcType:可以省略
  • parameterType:可以省略

如果参数只有⼀个的话,#{} ⾥⾯Just write the content of the.对于 ${} 来说,注意加单引号.

8.2 Map参数

准备map

 // 准备Map
Map<String,Object> paramMap = new HashMap<>();
paramMap.put("nameKey", "张三");
paramMap.put("ageKey", 20);

编写sql语句

 <select id="selectByParamMap" resultType="student">
select * from t_student where name = #{nameKey} and age = #{ageKey}
</select>

这种⽅式是⼿dynamic packagingMap集合,Each condition tokey和valueIn the form of storage to the collection.然后在使⽤的时候通过# {map集合的key}来取值.

8.3 实体类参数

准备数据

 Student student = new Student(null,"王二麻子",24,1.68,new Date(),'男');

编写sql语句

 <insert id="insertByStudent">
insert into t_student (id, name, age, height, birth, sex)
values (null,#{name},#{age},#{height},#{birth},#{sex});
</insert>

8.4 多参数

java程序

 SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectByNameAndAge("李四",18);

sql语句

 <select id="selectByNameAndAge" resultType="com.jm.pojo.Student">
select *
from t_student where name=#{name} and age=#{age};
</select>

实现原理:实际上在mybatis底层会创建⼀个map集合,以arg0/param1为key,以⽅Method on the parameters as value
参数为

  • arg0/arg1/agr2/arg3…
  • 或者param1/param2/param3…
  • 添加Param(“”)注解后,取代arga certain location

8.5 @Param注解(命名参数)

使⽤ @Param注解即可.这样可以增强可读性.

 List<Student> selectByNameAndAge(@Param("name") String name,@Param("age") Integer age);
 <select id="selectByNameAndAge" resultType="com.jm.pojo.Student">
select *
from t_student where name=#{name} and age=#{age};
</select>
 List<Student> students = mapper.selectByNameAndAge("李四",18);
students.forEach(student -> System.out.println(student));

核⼼:@Param(“这⾥Fill in this application is actuallymap集合的key”)

九、MyBatis查询语句

9.1 返回Car

When the results of a query,There is a corresponding entity class,And the query result is⼀条时:

 Car selectById(Long id);

9.2 返回List

When the query on the number of records is more than,必须使⽤集合接收.如果使⽤A single entity class receives will be abnormal.

List<Car> selectAll();

查询结果是⼀A word can make the⽤ListDoes the collection receive?当然可以.
If the query results for multiple,用单个Car实体类接收,会报异常:TooManyResultsException

9.3 返回Map

When the data returned,No suitable entity class corresponding to,可以采⽤Map集合接收.Field names dokey,Field values ​​dovalue. Query if can ensure that only⼀条数据,则返回⼀个Map集合即可.

Map<String, Object> selectByIdRetMap(Long id);
<select id="selectByIdRetMap" resultType="map">
select id,car_num carNum,brand,guide_price guidePrice,produce_time produc
eTime,car_type carType from t_car where id = #{id}
</select>

resultMap=“map”,这是因为mybatisBuilt in many aliases.

9.4 返回List

查询结果条数⼤于等于1条数据,则可以返回⼀个存储Map集合的List集合.

List<Map<String,Object>> selectAllRetListMap();

9.5 返回Map<String,Map>

拿Car的id做key,After take out the correspondingMapMore when gathering⽅便.

//添加注解,表示大Map
@MapKey("id")
Map<Long,Map<String,Object>> selectAllRetMap();

9.6 resultMap结果映射

The query result column names andjavaObject attribute names corresponding to not to do?

  • 第⼀种⽅式:as 给列起别名
  • 第⼆种⽅式:使⽤resultMap进⾏结果映射
  • 第三种⽅式:是否开启驼峰命名⾃动映射(配置settings)

使⽤resultMap进⾏结果映射

 <!-- resultMap: id:This result map logo,作为select标签的resultMap属性的值. type:The result set to map the class.可以使⽤别名. -->
<resultMap id="carResultMap" type="car">
<!--对象的唯⼀标识,官⽅解释是:为了提⾼mybatis的性能.建议写上.-->
<id property="id" column="id"/>
<result property="carNum" column="car_num"/>
<!--When the attribute name and database column names⼀致时,可以省略.But written advice.-->
<!--javaType⽤To specify the attribute types.jdbcType⽤To specify the column type.⼀can generally be omitted.-->
<result property="brand" column="brand" javaType="string" jdbcType="VARCHAR"/>
<result property="guidePrice" column="guide_price"/>
<result property="produceTime" column="produce_time"/>
<result property="carType" column="car_type"/>
</resultMap>
<!--resultMap属性的值必须和resultMap标签中id属性值⼀致.-->
<select id="selectAllByResultMap" resultMap="carResultMap">
select *
from t_car
</select>

是否开启驼峰命名⾃动映射
使⽤这种⽅The premise of the formula is:Property names followJava的命名规范,Database table column name to followSQL的命名规范.
Java命名规范:⾸字⺟⼩写,后⾯每个单词⾸字⺟⼤写,遵循驼峰命名⽅式.
SQL命名规范:全部⼩写,Pick between words⽤下划线分割.

⽐Such as the following corresponding relation:
在这里插入图片描述

如何启⽤该功能,在mybatis-config.xml⽂件中进⾏配置:

<!--放在properties标签后⾯-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

9.7 返回总记录条数

<!--long是别名,可参考mybatis中文网.-->
<select id="selectTotal" resultType="long">
select count(*) from t_car
</select>

十、动态SQL

10.1 if标签

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mybatis.mapper.CarMapper">
<select id="selectByMultiCondition" resultType="car">
select * from t_car where
<if test="brand != null and brand != ''">
brand like #{brand}"%"
</if>
<if test="guidePrice != null and guidePrice != ''">
and guide_price >= #{guidePrice}
</if>
<if test="carType != null and carType != ''">
and car_type = #{carType}
</if>
</select>
</mapper>
  • 如果第⼀conditions are empty,The remaining two conditions are not empty,会是怎样呢?
    • 报错了,SQL语法有问题,where后⾯出现了and.
    • 解决:可以where后⾯添加⼀Hengcheng⽴的条件.
  • If three conditions are empty,有影响吗?
    • Need in front of the first condition to addand

10.2 where标签

where标签的作⽤:让where⼦Other more dynamic intelligent.

  • All conditions is empty,whereLabel not generatewhere⼦句.
  • Automatic removal of certain conditions前面多余的and或or.
<select id="selectByMultiConditionWithWhere" resultType="car">
select * from t_car
<where>
<if test="brand != null and brand != ''">
and brand like #{brand}"%"
</if>
<if test="guidePrice != null and guidePrice != ''">
and guide_price >= #{guidePrice}
</if>
<if test="carType != null and carType != ''">
and car_type = #{carType}
</if>
</where>
</select>

10.3 trim标签

trim标签的属性:

  • prefix:在trimThe label before the statement in add content
  • suffix:在trimThe label after the statement in add content
  • prefixOverrides:前缀覆盖掉(去掉)
  • suffixOverrides:suffix is ​​overwritten(去掉)
<select id="selectByMultiConditionWithTrim" resultType="car">
select * from t_car
<trim prefix="where" suffixOverrides="and|or">
<if test="brand != null and brand != ''">
brand like #{brand}"%" and
</if>
<if test="guidePrice != null and guidePrice != ''">
guide_price >= #{guidePrice} and
</if>
<if test="carType != null and carType != ''">
car_type = #{carType}
</if>
</trim>
</select>

10.4 set标签

  • 主要使⽤在update语句当中
  • 作用:⽤来⽣成set关键字,At the same time to remove the last spare“,”
  • For example, we update only submit is not null field,If the submitted data is empty or"",So we would update this field.
<update id="updateWithSet">
update t_car
<set>
<if test="carNum != null and carNum != ''">car_num = #{carNum},</if>
<if test="brand != null and brand != ''">brand = #{brand},</if>
<if test="guidePrice != null and guidePrice != ''">guide_price = #{guidePrice},</if>
<if test="produceTime != null and produceTime != ''">produce_time = #{produceTime},</if>
<if test="carType != null and carType != ''">car_type = #{carType},</if>
</set>
where id = #{id}
</update>

10.5 choose when otherwise

The three tags are in⼀起使⽤的:
语法格式:

<choose>
<when></when>
<when></when>
<when></when>
<otherwise></otherwise>
</choose>

等同于:

if(){

}else if(){

}else if(){

}else if(){

}else{

}

sql语句

<select id="selectWithChoose" resultType="car">
select * from t_car
<where>
<choose>
<when test="brand != null and brand != ''">
brand like #{brand}"%"
</when>
<when test="guidePrice != null and guidePrice != ''">
guide_price >= #{guidePrice}
</when>
<otherwise>
produce_time >= #{produceTime}
</otherwise>
</choose>
</where>
</select>

10.6 foreach标签

Circular array or collection,动态⽣成sql,⽐如这样的SQL:

批量删除

  • 用in来删除
<!-- collection:集合或数组 item:The elements in the collection or array separator:分隔符 open:foreachLabel all the content in the beginning close:foreachAll the content in the end -->
<delete id="deleteBatchByForeach">
delete from t_car where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
  • ⽤or来删除
<delete id="deleteBatchByForeach2">
delete from t_car where
<foreach collection="ids" item="id" separator="or">
id = #{id}
</foreach>
</delete>

批量添加

<insert id="insertBatchByForeach">
insert into t_car values
<foreach collection="cars" item="car" separator=",">
(null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
</foreach>
</insert>

10.7 sql标签与include标签

  • sql标签⽤来声明sql⽚段
  • include标签⽤来将声明的sql⽚Section contains asql语句当中
  • 作⽤:代码复⽤.易维护
<sql id="carCols">id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType</sql>
<select id="selectAllRetMap" resultType="map">
select <include refid="carCols"/> from t_car
</select>
<select id="selectAllRetListMap" resultType="map">
select <include refid="carCols"/> carType from t_car
</select>
<select id="selectByIdRetMap" resultType="map">
select <include refid="carCols"/> from t_car where id = #{id}
</select>

十一、MyBatisThe advanced mapping and lazy loading

11.1 多对一

在这里插入图片描述

多种⽅式,常⻅including three:

  • 第⼀种⽅式:⼀条SQL语句,Cascade attribute mapping.
  • 第⼆种⽅式:⼀条SQL语句,association.
  • 第三种⽅式:两条SQL语句,分步查询.(这种⽅regular⽤:优点⼀is reproducible⽤.优点⼆是⽀Hold lazy plus 载.)

第⼀种方式:Cascade attribute mapping

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mybatis.mapper.StudentMapper">
<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<result property="clazz.cid" column="cid"/>
<result property="clazz.cname" column="cname"/>
</resultMap>
<select id="selectBySid" resultMap="studentResultMap">
select s.*, c.* from t_student s join t_clazz c on s.cid = c.cid where sid = #{sid}
</select>
</mapper>

第⼆种方式:association

<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz" javaType="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
</association>
</resultMap>

第三种方式:分步查询

Step-by-step advantages:

  • 第⼀个优点:代码复⽤性增强.
  • 第⼆个优点:⽀持延迟加载.【Temporarily not to access data can not query first.提⾼程序的执⾏效率.】

主(多的一方)

<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz" select="com.powernode.mybatis.mapper.ClazzMapper.selectByCid" column="cid"/>
</resultMap>
<select id="selectBySid" resultMap="studentResultMap">
select s.* from t_student s where sid = #{sid}
</select>

副(一的一方)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.powernode.mybatis.mapper.ClazzMapper">
<select id="selectByCid" resultType="Clazz">
select * from t_clazz where cid = #{cid}
</select>
</mapper>

11.2 多对⼀延迟加载

1)要想⽀持延迟加载,⾮常简单,只需要在association标签中添加fetchType=“lazy”即可.

<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz" select="com.powernode.mybatis.mapper.ClazzMapper.selectByCid" column="cid" fetchType="lazy"/>
</resultMap>

2)在mybatisHow to open a global delay in loading?需要setting配置,如下:

<settings>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>

把SQL映射文件的fetchType="lazy"去掉.

3)Open the global delay loading after,所有的sql都会⽀持延迟加载,如果某个sqlYou don't want it⽀What a lazy loading?
将fetchType设置为eager:

<resultMap id="studentResultMap" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="clazz" select="com.powernode.mybatis.mapper.ClazzMapper.selectByCid" column="cid" fetchType="eager"/>
</resultMap>

这样的话,针对某个特定的sql,It was shut down delay loading mechanism.

11.3 ⼀对多

在这里插入图片描述

⼀Many implementations,通常是在⼀的⼀⽅中有List集合属性.

⼀For the implementation of more usually includes two implementations⽅式:

  • 第⼀种⽅式:collection
  • 第⼆种⽅式:分步查询

第⼀种方式:collection

<resultMap id="clazzResultMap" type="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<collection property="stus" ofType="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
</collection>
</resultMap>
<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
select * from t_clazz c join t_student s on c.cid = s.cid where c.cid = #{cid}
</select>

注意是ofType,表示“集合中的类型”.

第⼆种方式:分步查询

主(一的一方)

<resultMap id="clazzResultMap" type="Clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<!--主要看这⾥-->
<collection property="stus" select="com.powernode.mybatis.mapper.StudentMapper.selectByCid" column="cid"/>
</resultMap>
<!--sqlStatement also changed-->
<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
select * from t_clazz c where c.cid = #{cid}
</select>

副(多的一方)

<select id="selectByCid" resultType="Student">
select * from t_student where cid = #{cid}
</select>

11.4 ⼀For more lazy loading

⼀For more lazy loading mechanism and the⼀是⼀样的.The same is through two⽅式:

  • 第⼀种:fetchType=“lazy”
  • 第⼆种:修改全局的配置setting,lazyLoadingEnabled=true,If open global lazy loading,想让某个 sql不使⽤延迟加载:fetchType=“eager”

十二、MyBatis的缓存

缓存:cache

Cached work⽤:通过减少IO的⽅式,来提⾼程序的执⾏效率.

mybatis的缓存:将select语句The query results in the cache(内存)当中,下⼀This is the second timeselect语句的话,直 Pick up from the cache,不再查数据库.⼀⽅⾯是减少了IO.另⼀⽅⾯不再执⾏Tedious lookup algorithm.效率大大提升.

mybatis缓存包括:

  • ⼀级缓存:将查询到的数据存储到SqlSession中.
  • ⼆级缓存:将查询到的数据存储到SqlSessionFactory中.
  • Or integration other third⽅的缓存:⽐如EhCache【Java语⾔开发的】、Memcache【C语⾔开发的】等.

Cache only forDQL语句,That is to say, corresponding caching mechanismselect语句.

12.1 ⼀级缓存

12.1.1 ⼀Level cache default is open,范围是sqlSession

不需要做任何配置.

原理:只要使⽤同⼀个SqlSession对象执⾏同⼀条SQL语句,就会⾛缓存.

 @Test
public void testSelectById2() throws Exception {

SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession1 = sqlSessionFactory.openSession();
CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(165L);
System.out.println(car1);
Car car2 = mapper1.selectById(165L);
System.out.println(car2);
}

在这里插入图片描述

12.1.2 Don't walk two cases of cache?

  • 第⼀种:不同的SqlSession对象.
  • 第⼆种:Query conditions change.
 @Test
public void testSelectById() throws Exception {

SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession1 = sqlSessionFactory.openSession();
CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(166L);
System.out.println(car1);
//Query conditions changed,不走缓存
Car car2 = mapper1.selectById(165L);
System.out.println(car2);
//不同的sqlSession对象,不走缓存
SqlSession sqlSession2 = sqlSessionFactory.openSession();
CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
Car car3 = mapper2.selectById(165L);
System.out.println(car3);
Car car4 = mapper2.selectById(165L);
System.out.println(car4);
}

在这里插入图片描述

12.1.3 ⼀Level cache invalidation of two things?

  • 第⼀种:第⼀times query and th⼆between queries,⼿Move emptied⼀级缓存
  • 第⼆种:第⼀times query and th⼆between queries,执⾏Increases the deletion operation.(no matter which table)
 @Test
public void testSelectById2() throws Exception {

SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession1 = sqlSessionFactory.openSession();
CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(165L);
System.out.println(car1);
//手动清除一级缓存
//sqlSession1.clearCache();
//第⼀times query and th⼆Between the query executionupdate、insert、delete操作,一级缓存失效
mapper1.insert(new Car(null,"8888","兰德酷路泽",67.0,"2018-12-05","新能源"));
Car car2 = mapper1.selectById(165L);
System.out.println(car2);
}

12.2 二级缓存

12.2.1 二级缓存的范围是SqlSessionFactory

12.2.2 使⽤The second level cache needs to have the following several conditions:

1.<setting name=“cacheEnabled” value=“true”> Overall to open or close all mapper configuration⽂is configured in the file any cache.默认就是true⽆需设置.
2. 在需要使⽤⼆级缓存的SqlMapper.xml⽂A configuration is added:<cache />
3. 使⽤⼆Level cache object of entity class must be serializable,也就是必须实现java.io.Serializable接⼝
4. SqlSessionObjects close or submitted,⼀Cache the data will be written⼊到⼆level cache.此时⼆level cache⽤.

测试二级缓存:

 @Test
public void testSelectById3() throws Exception{

SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession1 = sqlSessionFactory.openSession();
CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
Car car1 = mapper1.selectById(165L);
System.out.println(car1);
//关键一步
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
Car car2 = mapper2.selectById(165L);
System.out.println(car2);
}

在这里插入图片描述

12.2.3 The second level cache invalidation conditions?

As long as the two queries appeared to add deletion operation between.⼆Level cache will fail.【⼀Level cache will also fail】

12.2.4 二级缓存的相关配置<cache />

在这里插入图片描述

  1. eviction:Specify the elimination algorithm removed from the cache object.默认采⽤LRU策略.
    a. LRU:Least Recently Used.最近最少使⽤.Priority selection made in the interval time⽤The lowest frequency object.(其 Actually there is⼀an elimination algorithmLFU,最不常⽤.)
    b. FIFO:First In First Out.⼀Kind of fifo data cache.先进⼊⼆Cache object to be eliminated first.
    c. SOFT:软引⽤.Eliminate soft leads⽤指向的对象.具体算法和JVMGarbage collection algorithms about.
    d. WEAK:弱引⽤.Eliminate weak leads⽤指向的对象.具体算法和JVMGarbage collection algorithms about.
  2. flushInterval:
    ⼆Level cache refresh interval.单位毫秒.如果没有设置.Means don't refresh the cache,只要内存⾜够⼤,⼀ straight to⼆Level cache cache data.除⾮执⾏additions and deletions.
  3. readOnly:
    a. true:多条相同的sql语句执⾏After the object returned is Shared with⼀个.性能好.But a multi-threaded concurrent may 会存在安全问题.
    b. false:多条相同的sql语句执⾏After the object returned is copy,调⽤了clone⽅法.性能⼀般.但安全.
  4. size:
    设置⼆Level cache can store up tojava对象数量.默认值1024.

12.3 MyBatis集成EhCache

12.3.1 集成EhCache是为了代替mybatis自带的⼆级缓存.

⼀级缓存是⽆replaced by law.
mybatisProvide the answer⼝,Can also integrate the third⽅的缓存组件.⽐如EhCache、Memcache等.都可以. EhCache是Java写的.Memcache是C语⾔写的.所以mybatis集成EhCachemore common⻅.

12.3.2 操作步骤

第⼀步:引⼊mybatis整合ehcache的依赖

<!--mybatis集成ehcache的组件-->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<!--ehcache需要slf4j的⽇志组件,log4j不好使-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>test</scope>
</dependency>

第⼆步:In the class under the root of the newechcache.xml⽂件,And provide the following configuration information.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
<!--磁盘存储:Will cache temporarily not that⽤的对象,转移到硬盘,类似于Windows系统的虚拟内存-->
<diskStore path="e:/ehcache"/>
<!--defaultCache:默认的管理策略-->
<!--eternal:设定缓存的elements是否永远不过期.如果为true,The cached data always have 效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断-->
<!--maxElementsInMemory:在内存中缓存的element的最⼤数⽬-->
<!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上-->
<!--diskPersistent:是否在磁盘上持久化.指重启jvm后,数据是否有效.默认为false-->
<!--timeToIdleSeconds:对象空闲时间(单位:秒),Indicates that there are many objects⻓Time is not access will be lost 效.只对eternal为false的有效.默认值0,表示⼀directly accessible-->
<!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间. 只对eternal为false的有效.默认值0,表示⼀directly accessible-->
<!--memoryStoreEvictionPolicy:缓存的3 种清空策略-->
<!--FIFO:first in first out (先进先出)-->
<!--LFU:Less Frequently Used (最少使⽤).意思是⼀Straight since at least be made⽤的.Cached meta 素有⼀个hit 属性,hit 值最⼩Clear the cache will be-->
<!--LRU:Least Recently Used(最近最少使⽤). (ehcache 默认值).Cache element has⼀ 个时间戳,当缓存容量满了,⽽⼜Need to make room⽅To cache new elements,So the existing cache element timestamp The elements of the farthest from the current time will be clear the cache-->
<defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
</ehcache>

第三步:修改SqlMapper.xml⽂件中的<cache/>标签,添加type属性.

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

第四步:Write test programs make⽤.

十三、MyBatis的逆向工程

The so-called reverse⼯程是:According to the database table reverse⽣成Java的pojo类,SqlMapper.xml⽂件,以及Mapper接⼝类等.

要完成这个⼯作,Need help⼈Written reverse⼯program plugin.

思考:使⽤这个插件的话,What information is need for the plug-in configuration?

  • pojo类名、包名以及⽣成位置.
  • SqlMapper.xml⽂item name and ⽣成位置.
  • Mapper接⼝名以及⽣成位置.
  • 连接数据库的信息.
  • Specify which tables are involved in the reverse⼯程.

13.1 操作步骤

第⼀步:基础环境准备
创建模块,打包⽅式:jar
第⼆步:在pomAdd reverse⼯program plugin

 <!--定制构建过程-->
<build>
<!--Configurable multiple plug-ins-->
<plugins>
<!--其中的⼀个插件:mybatis逆向⼯program plugin-->
<plugin>
<!--插件的GAV坐标-->
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.1</version>
<!--允许覆盖-->
<configuration>
<overwrite>true</overwrite>
</configuration>
<!--插件的依赖-->
<dependencies>
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

第三步:配置generatorConfig.xml
该⽂A name must be called:generatorConfig.xml
该⽂A must in class under the root of.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- targetRuntime有两个值: MyBatis3Simple:⽣As is the base version,Basic to add and delete. MyBatis3:⽣As the enhanced version,In addition to basic add and delete and complicated to add and delete. -->
<context id="DB2Tables" targetRuntime="MyBatis3Simple">
<!--防⽌⽣into duplicate code-->
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
<commentGenerator>
<!--是否去掉⽣成⽇期-->
<property name="suppressDate" value="true"/>
<!--是否去除注释-->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--连接数据库信息-->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/jmpower" userId="root" password="021107">
</jdbcConnection>
<!-- ⽣成pojo包名和位置 -->
<javaModelGenerator targetPackage="com.jm.pojo" targetProject="src/main/java">
<!--是否开启⼦包-->
<property name="enableSubPackages" value="true"/>
<!--Whether to remove the field name before and after the empty⽩-->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- ⽣成SQL映射⽂A package name and the position of -->
<sqlMapGenerator targetPackage="com.jm.mapper" targetProject="src/main/resources">
<!--是否开启⼦包-->
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- ⽣成Mapper接⼝的包名和位置 -->
<javaClientGenerator type="xmlMapper" targetPackage="com.jm.mapper" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- Name of the table and the corresponding entity class name-->
<table tableName="t_car" domainObjectName="Car"/>
</context>
</generatorConfiguration>

第四步:运⾏插件
在这里插入图片描述

13.2 Test of whether to use reverse engineering

第⼀步:环境准备

  • 依赖:mybatis依赖、mysql驱动依赖、junit依赖、logback依赖
  • jdbc.properties
  • mybatis-config.xml
  • logback.xml

第⼆步:编写测试程序

package com.powernode.mybatis.test;
import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.pojo.CarExample;
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 org.junit.Test;
import java.math.BigDecimal;
import java.util.List;
public class GeneratorTest {

@Test
public void testGenerator() throws Exception{

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder
().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 增
/*Car car = new Car(); car.setCarNum("1111"); car.setBrand("⽐亚迪唐"); car.setGuidePrice(new BigDecimal(30.0)); car.setProduceTime("2010-10-12"); car.setCarType("燃油⻋"); int count = mapper.insert(car); System.out.println("插⼊了⼏条记录:" + count);*/
// 删
/*int count = mapper.deleteByPrimaryKey(83L); System.out.println("删除了⼏条记录:" + count);*/
// 改
// 根据主键修改
/*Car car = new Car(); car.setId(89L); car.setGuidePrice(new BigDecimal(20.0)); car.setCarType("新能源"); int count = mapper.updateByPrimaryKey(car); System.out.println("更新了⼏条记录:" + count);*/
// 根据主键选择性修改
/*car = new Car(); car.setId(89L); car.setCarNum("3333"); car.setBrand("宝⻢520Li"); car.setProduceTime("1999-01-10"); count = mapper.updateByPrimaryKeySelective(car); System.out.println("更新了⼏条记录:" + count);*/
// 查⼀个
Car car = mapper.selectByPrimaryKey(89L);
System.out.println(car);
// 查所有
List<Car> cars = mapper.selectByExample(null);
cars.forEach(c -> System.out.println(c));
// 多条件查询
// QBC ⻛格:Query By Criteria ⼀种查询⽅式,⽐较⾯向对象,看不到sql语句.
CarExample carExample = new CarExample();
carExample.createCriteria()
.andBrandEqualTo("丰⽥霸道")
.andGuidePriceGreaterThan(new BigDecimal(60.0));
carExample.or().andProduceTimeBetween("2000-10-11", "2022-10-11");
mapper.selectByExample(carExample);
sqlSession.commit();
}
}

十四、MyBatis使用PageHelper

14.1 limit分页

mysql的limit后⾯两个数字:

  • 第⼀个数字:startIndex(起始下标.下标从0开始.)
  • 第⼆个数字:pageSize(每页According to the number of records)

假设已知⻚码pageNum,还有每⻚According to the number of recordspageSize,第⼀A number can dynamically obtain?

  • startIndex = (pageNum - 1) * pageSize

14.2 PageHelper插件

使⽤PageHelper插件进⾏分⻚,更加的便捷.

操作步骤

第⼀步:引⼊依赖

<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.1</version>
</dependency>

第⼆步:在mybatis-config.xml⽂A configuration in the plugin

<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

第三步:编写Java代码

 @Test
public void testSelectAll(){

SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
//一定要DQL之前,开启分页功能
int pageNum=2;
int pageSize=3;
PageHelper.startPage(pageNum,pageSize);
//执行查询语句
List<Car> cars = mapper.selectAll();
//Encapsulate the paging information objectnew PageInfo()
//PageInfo对象是PageHelper插件提供的,Object to encapsulate relevant information
PageInfo<Car> carPageInfo = new PageInfo<>(cars, 3);
System.out.println(carPageInfo);
SqlSessionUtil.close(sqlSession);
}

执行结果:
PageInfo{
pageNum=2, pageSize=2, size=2, startRow=3, endRow=4, total=6, pages=3,
list=Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=
6, pages=3, reasonable=false, pageSizeZero=false}
[Car{id=86, carNum=‘1234’, brand=‘丰⽥霸道’, guidePrice=50.5, produceTime
=‘2020-10-11’, carType=‘燃油⻋’},
Car{id=87, carNum=‘1234’, brand=‘丰⽥霸道’, guidePrice=50.5, produceTime
=‘2020-10-11’, carType=‘燃油⻋’}],
prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPa
ge=true, hasNextPage=true,
navigatePages=5, navigateFirstPage=1, navigateLastPage=3, navigatepageNum
s=[1, 2, 3]
}

十五、MyBatis的注解式开发

mybatisAlso provides the annotation type development⽅式,采⽤注解可以减少Sql映射⽂件的配置. 当然,使⽤Annotation type development,sql语句是写在java程序中的,这种⽅formula will also给sqlStatement of the maintenance cost.

官⽅是这么说的:

使⽤Annotations to map simple statements would make the code more concise,But for a little more complicated⼀点的语句,Java 注解不仅力不从心,还会 This is complicated SQL 语句更加混乱不堪. 因此,If you need to do⼀Some very complex operations,最好用 XML 来映射语句.

使⽤Annotation of writing complicatedSQL是这样的:

在这里插入图片描述

原则:简单sql可以注解.复杂sql使⽤xml.

15.1 @Insert

 @Insert("insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})")
int insert(Car car);

15.2 @Delete

 @Delete("delete from t_car where id=#{id};")
int deleteById(int id);

15.3 @Update

 @Update("update t_car " +
"set " +
"car_num=#{carNum},brand=#{brand},guide_price=#{guidePrice},produce_time=#{produceTime},car_type=#{carType} " +
"where id=#{id};")
int update(Car car);

15.4 @Select

 @Select("select * from t_car where id=#{id};")
@Results({

@Result(property = "id",column = "id"),
@Result(property = "carNum",column = "car_num"),
@Result(property = "brand",column = "brand"),
@Result(property = "guidePrice",column = "guide_price"),
@Result(property = "produceTime",column = "produce_time"),
@Result(property = "carType",column = "car_type")
})
Car selectById(int id);
copyright:author[Jm],Please bring the original link to reprint, thank you. https://en.javamana.com/2022/266/202209230828296818.html