《MyBatis CRUD实战与核心配置详解:从基础操作到高级应用》

一、使用MyBatis完成CRUD

  • 准备工作

    • 创建module(Maven的普通Java模块):mybatis-002-crud

    • pom.xml

      • 打包方式jar

      • 依赖:

        • mybatis依赖

        • mysql驱动依赖

        • junit依赖

        • logback依赖

    • mybatis-config.xml放在类的根路径下

    • CarMapper.xml放在类的根路径下

    • logback.xml放在类的根路径下

    • 提供utils.SqlSessionUtil工具类

1.insert(Create)

分析以下SQL映射文件中SQL语句存在的问题

<?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先随便写-->
<mapper namespace="car"><insert id="insertCar">insert into t_car(car_num,brand,guide_price,produce_time,car_type) values('103', '奔驰E300L', 50.3, '2022-01-01', '燃油车')</insert>
</mapper>

存在的问题是:SQL语句中的值不应该写死,值应该是用户提供的。之前的JDBC代码是这样写的:

// JDBC中使用 ? 作为占位符。那么MyBatis中会使用什么作为占位符呢?
String sql = "insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(?,?,?,?,?)";
// ......
// 给 ? 传值。那么MyBatis中应该怎么传值呢?
ps.setString(1,"103");
ps.setString(2,"奔驰E300L");
ps.setDouble(3,50.3);
ps.setString(4,"2022-01-01");
ps.setString(5,"燃油车");

在MyBatis中可以这样做:

在Java程序中,将数据放到Map集合中

在sql语句中使用 #{map集合的key} 来完成传值,#{} 等同于JDBC中的 ? ,#{}就是占位符

Java程序这样写:

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 {@Testpublic 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集合给sql语句传递数据)int count = sqlSession.insert("insertCar", map);System.out.println("插入了几条记录:" + count);}
}

SQL语句这样写:

<?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先随便写-->
<mapper namespace="car"><insert id="insertCar">insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{k1},#{k2},#{k3},#{k4},#{k5})</insert>
</mapper>

⑴.演示代码运行

mybatis-config.xml   这是数据库的的配置文件

CarMapper.xml   这是对应表操作的文件

测试运行文件

运行前的数据库

#{} 的里面必须填写map集合的key,不能随便写。运行测试程序,查看数据库:

⑵如果#{}里写的是map集合中不存在的key会有什么问题?

运行程序:

通过测试,看到程序并没有报错。正常执行。不过 #{kk} 的写法导致无法获取到map集合中的数据,最终导致数据库表car_num插入了NULL。

在以上sql语句中,可以看到#{k1} #{k2} #{k3} #{k4} #{k5}的可读性太差,为了增强可读性,我们可以将Java程序做如下修改:

运行程序,查看数据库表:

⑶使用Map集合可以传参,那使用pojo(简单普通的java对象)可以完成传参吗?测试一下:

  • 第一步:定义一个pojo类Car,提供相关属性。

package org.example1.pojo;/*** 封装汽车相关信息的pojo类。普通的java类。*/
public class Car {// 数据库表当中的字段应该和pojo类的属性一一对应。// 建议使用包装类,这样可以防止null的问题。private Long id;private String carNum;private String brand;private Double guidePrice;private String produceTime;private String carType;@Overridepublic 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 String getXyz() {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程序

  • 第三步:SQL语句

  • 运行程序,查看数据库表:

⑷#{} 里写的是POJO的属性名,如果写成其他的会有问题吗?

运行程序,出现了以下异常:

错误信息中描述:在Car类中没有找到a属性的getter方法。 修改POJO类Car的代码,只将getCarNum()方法名修改为getA(),其他代码不变,如下:

再运行程序,查看数据库表中数据:

经过测试得出结论:

如果采用map集合传参,#{} 里写的是map集合的key,如果key不存在不会报错,数据库表中会插入NULL。

如果采用POJO传参,#{} 里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get方法不存在会报错。

注意:其实传参数的时候有一个属性parameterType,这个属性用来指定传参的数据类型,不过这个属性是可以省略的

<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="org.example1.pojo.Car">insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>
通过这个测试,得出一个结论:严格意义上来说:如果使用POJO对象传递值的话,#{}这个大括号中到底写什么?写的是get方法的方法名去掉get,然后将剩下的单词首字母小写,然后放进去。例如:getUsername() --> #{username}例如:getEmail() --> #{email}....
也就是说mybatis在底层给?传值的时候,先要获取值,怎么获取的?调用了pojo对象的get方法。例如:car.getCarNum(),car.getCarType(),car.getBrand()

2.delete(Delete)

需求:根据car_num进行删除。

SQL语句这样写:

CarMapper.xml

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

Java程序这样写:

运行前的数据库

运行结果:

注意:当占位符只有一个的时候,${} 里面的内容可以随便写。

3.update(Update)

需求:修改id=3的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代码如下:

    @Testpublic void testUpdateCarByPOJO(){// 准备数据Car car = new Car();car.setId(3L);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);sqlSession.commit();//注意要提交sqlSession.close();}

运行结果:

4.select(Retrieve)

select语句和其它语句不同的是:查询会有一个结果集。来看mybatis是怎么处理结果集的!!!

⑴.查询一条数据

需求:查询id为1的Car信息 SQL语句如下:

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

Java程序如下:

   @Testpublic void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();// 执行DQL语句。查询。根据id查询。返回结果一定是一条。// mybatis底层执行了select语句之后,一定会返回一个结果集对象:ResultSet// JDBC中叫做ResultSet,接下来就是mybatis应该从ResultSet中取出数据,封装java对象。Object car = sqlSession.selectOne("selectCarById", 1);System.out.println(car);sqlSession.close();}

运行结果如下:

### Error querying database.  Cause: org.apache.ibatis.executor.ExecutorException: 
    A query was run and no Result Maps were found for the Mapped Statement 'car.selectCarById'.  

【翻译】:对于一个查询语句来说,没有找到查询的结果映射。


    It's likely that neither a Result Type nor a Result Map was specified.                        

【翻译】:很可能既没有指定结果类型,也没有指定结果映射。

以上的异常大致的意思是:对于一个查询语句来说,你需要指定它的“结果类型”或者“结果映射”。 所以说,你想让mybatis查询之后返回一个Java对象的话,至少你要告诉mybatis返回一个什么类型的Java对象,可以在<select>标签中添加resultType属性,用来指定查询要转换的类型:

  <select id="selectCarById" resultType="org.example1.pojo.Car">select * from t_car where id = #{id}</select>

运行结果:

运行后之前的异常不再出现了,这说明添加了resultType属性之后,解决了之前的异常,可以看出resultType是不能省略的。 仔细观察控制台的日志信息,不难看出,结果查询出了一条。并且每个字段都查询到值了:  Row: 1, 1001, 宝马520Li, 10.00, 2020-10-11, 燃油车

但是奇怪的是返回的Car对象,只有id和brand两个属性有值,其它属性的值都是null,这是为什么呢?我们来观察一下查询结果列名和Car类的属性名是否能一一对应:

查询结果集的列名:id, car_num, brand, guide_price, produce_time, car_type

Car类的属性名:id, carNum, brand, guidePrice, produceTime, carType

通过观察发现:只有id和brand是一致的,其他字段名和属性名对应不上,这是不是导致null的原因呢?我们尝试在sql语句中使用as关键字来给查询结果列名起别名试试:

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

运行结果如下:

通过测试得知,如果当查询结果的字段名和java类的属性名对应不上的话,可以采用as关键字起别名,当然还有其它解决方案,我们后面再看

⑵查询多条数据

需求:查询所有的Car信息。 SQL语句如下:

    <!--虽然结果是List集合,但是resultType属性需要指定的是List集合中元素的类型。--><select id="selectCarAll" resultType="org.example1.pojo.Car"><!--记得使用as起别名,让查询结果的字段名和java类的属性名对应上。-->selectid, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carTypefromt_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));
}

运行结果如下:

注意:resultType还是指定要封装的结果集的类型。不是指定List类型,是指定List集合中元素的类型。
selectList方法:mybatis通过这个方法就可以得知你需要一个List集合。它会自动给你返回一个List集合。

5.关于SQL Mapper的namespace

在SQL Mapper配置文件中<mapper>标签的namespace属性可以翻译为命名空间,这个命名空间主要是为了防止sqlId冲突的。 创建CarMapper2.xml文件,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car2"><!--虽然结果是List集合,但是resultType属性需要指定的是List集合中元素的类型。--><select id="selectCarAll" resultType="org.example1.pojo.Car"><!--记得使用as起别名,让查询结果的字段名和java类的属性名对应上。-->selectid, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carTypefromt_car</select></mapper>

不难看出,CarMapper.xml和CarMapper2.xml文件中都有 id="selectCarAll" 将CarMapper2.xml配置到mybatis-config.xml文件中。

CarMapper.xml

编写Java代码如下:

    @Testpublic void testSelectCarAll(){// 获取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 Statements集合中不明确(请尝试使用包含名称空间的全名,或重命名其中一个条目)
  【大致意思是】selectCarAll重名了,你要么在selectCarAll前添加一个名称空间,要么你改个其它名字。

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核心配置文件详解

<?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><settings><setting name="logImpl" value="STDOUT_LOGGING" /></settings><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/jdbc"/><property name="username" value="root"/><property name="password" value="abc123"/></dataSource></environment></environments><mappers><!--sql映射文件创建好之后,需要将该文件路径配置到这里--><mapper resource="Carmapper.xml"/><mapper resource="Carmapper2.xml"/></mappers>
</configuration>
  • configuration:根标签,表示配置信息。

  • environments:环境(多个),以“s”结尾表示复数,也就是说mybatis的环境可以配置多个数据源。

    • default属性:表示默认使用的是哪个环境,default后面填写的是environment的id。default的值只需要和environment的id值一致即可

  • environment:具体的环境配置(主要包括:事务管理器的配置 + 数据源的配置

    • id:给当前环境一个唯一标识,该标识用在environments的default后面,用来指定默认环境的选择。

<!--一般一个数据库会对应一个SqlSessionFactory对象。-->
<!--一个环境environment会对应一个SqlSessionFactory对象-->
  • transactionManager:配置事务管理器

    • type属性:指定事务管理器具体使用什么方式,可选值包括两个

      • JDBC:使用JDBC原生的事务管理机制。底层原理:事务开启conn.setAutoCommit(false); ...处理业务...事务提交conn.commit();

      • MANAGED:交给其它容器来管理事务,比如WebLogic、JBOSS等。如果没有管理事务的容器,则没有事务。没有事务的含义:只要执行一条DML语句,则提交一次

  • dataSource:指定数据源

    • type属性:用来指定具体使用的数据库连接池的策略,可选值包括三个

      • UNPOOLED:采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。

        • property可以是:

          • driver 这是 JDBC 驱动的 Java 类全限定名。

          • url 这是数据库的 JDBC URL 地址。

          • username 登录数据库的用户名。

          • password 登录数据库的密码。

          • defaultTransactionIsolationLevel 默认的连接事务隔离级别。

          • defaultNetworkTimeout 等待数据库操作完成的默认网络超时时间(单位:毫秒)

      • POOLED:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现。

        • property可以是(除了包含UNPOOLED中之外):

          • poolMaximumActiveConnections 在任意时间可存在的活动(正在使用)连接数量,默认值:10

          • poolMaximumIdleConnections 任意时间可能存在的空闲连接数。

          • 其它....

      • JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。如果不是web或者maven的war工程,JNDI是不能使用的。

        • property可以是(最多只包含以下两个属性):

          • initial_context 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。

          • data_source 这是引用数据源实例位置的上下文路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。

  • mappers:在mappers标签中可以配置多个sql映射文件的路径。

  • mapper:配置某个sql映射文件的路径

    • resource属性:使用相对于类路径的资源引用方式

    • url属性:使用完全限定资源定位符(URL)方式

1.environment

<!--一般一个数据库会对应一个SqlSessionFactory对象。-->

<!--一个环境environment会对应一个SqlSessionFactory对象-->

<?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><!--default表示默认使用的环境。--><!--默认环境什么意思?当你使用mybatis创建SqlSessionFactory对象的时候,没有指定环境的话,默认使用哪个环境。--><environments default="production"><!--其中的一个环境。连接的数据库是jdbc--><!--一般一个数据库会对应一个SqlSessionFactory对象。--><!--一个环境environment会对应一个SqlSessionFactory对象--><!--开发环境--><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/jdbc"/><property name="username" value="root"/><property name="password" value="abc123"/></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/car"/><property name="username" value="root"/><property name="password" value="abc123"/></dataSource></environment></environments><mappers><mapper resource="CarMapper.xml"/></mappers>
</configuration>

CarMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//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 values(null,'8888','沃尔沃',30.0,'2000-11-11','燃油车')</insert>
</mapper>

test

    @Testpublic void testEnvironment() throws Exception {// 获取SqlSessionFactory对象(采用默认的方式获取)SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();// 这种方式就是获取的默认环境SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession = sqlSessionFactory.openSession();// 执行SQL语句sqlSession.insert("car.insertCar");sqlSession.commit();sqlSession.close();// 这种方式就是通过环境id来使用指定的环境SqlSessionFactory sqlSessionFactory1 = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"), "dev");SqlSession sqlSession1 = sqlSessionFactory1.openSession();// 执行SQL语句sqlSession1.insert("car.insertCar");sqlSession1.commit();sqlSession1.close();}

运行前数据库

运行后:

2.transactionManager

transactionManager标签:1.作用:配置事务管理器。指定mybatis具体使用什么方式去管理事务。2.type属性有两个值:第一个:JDBC: 使用原生的JDBC代码来管理事务。conn.setAutoCommit(false);....conn.commit();第二个:MANAGED:mybatis不再负责事务的管理,将事务管理交给其它的JEE(JavaEE)容器来管理。例如:spring3. 大小写无所谓。不缺分大小写。但是不能写其他值。只能是二选一:jdbc、managed4. 在mybatis中提供了一个事务管理器接口:Transaction该接口下有两个实现类:JdbcTransactionManagedTransaction如果type="JDBC",那么底层会实例化JdbcTransaction对象。如果type="MANAGED",那么底层会实例化ManagedTransaction

当事务管理器是:JDBC

  • 采用JDBC的原生事务机制:

    • 开启事务:conn.setAutoCommit(false);

    • 处理业务......

    • 提交事务:conn.commit();

当事务管理器是:MANAGED

  • 交给容器去管理事务,但目前使用的是本地程序,没有容器的支持,当mybatis找不到容器的支持时:没有事务。也就是说只要执行一条DML语句,则提交一次。

3.dataSource

dataSource配置:1.dataSource被称为数据源。2.dataSource作用是什么?为程序提供Connection对象。(但凡是给程序提供Connection对象的,都叫做数据源。)3.数据源实际上是一套规范。JDK中有这套规范:javax.sql.DataSource(这个数据源的规范,这套接口实际上是JDK规定的。)4.我们自己也可以编写数据源组件,只要实现javax.sql.DataSource接口就行了。实现接口当中所有的方法。这样就有了自己的数据源。比如你可以写一个属于自己的数据库连接池(数据库连接池是提供连接对象的,所以数据库连接池就是一个数据源)。5.常见的数据源组件有哪些呢【常见的数据库连接池有哪些呢】?阿里巴巴的德鲁伊连接池:druidc3p0dbcp....6. type属性用来指定数据源的类型,就是指定具体使用什么方式来获取Connection对象:type属性有三个值:必须是三选一。type="[UNPOOLED|POOLED|JNDI]"UNPOOLED:不使用数据库连接池技术。每一次请求过来之后,都是创建新的Connection对象。POOLED:使用mybatis自己实现的数据库连接池。JNDI:集成其它第三方的数据库连接池。JNDI是一套规范。谁实现了这套规范呢?大部分的web容器都实现了JNDI规范:例如:Tomcat、Jetty、WebLogic、WebSphere,这些服务器(容器)都实现了JNDI规范。JNDI是:java命名目录接口。Tomcat服务器实现了这个规范。

⑴当type是UNPOOLED

UNPOOLED不会使用连接池,每一次都会新建JDBC连接对象。

test

    @Testpublic void testDataSource() throws Exception{SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();// sqlSessionFactory对象:一个数据一个。不要频繁创建该对象。SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));// 通过sqlSessionFactory对象可以开启多个会话。// 会话1SqlSession sqlSession1 = sqlSessionFactory.openSession();sqlSession1.insert("car.insertCar");sqlSession1.commit();sqlSession1.close(); // 因为要测试连接池的效果,关闭是需要的。别忘了,要不然测不出来。// 会话2SqlSession sqlSession2 = sqlSessionFactory.openSession();sqlSession2.insert("car.insertCar");sqlSession2.commit();sqlSession2.close();}

⑵type="POOLED

修改配置文件mybatis-config3.xml中的配置:

<dataSource type="POOLED">

Java测试程序不需要修改,直接执行,看控制台输出:

通过测试得出:UNPOOLED不会使用连接池,每一次都会新建JDBC连接对象。POOLED会使用数据库连接池。【这个连接池是mybatis自己实现的。】

重点说一下type="POOLED"的时候,它的属性有哪些?

<?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><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/jdbc"/><property name="username" value="root"/><property name="password" value="abc123"/><!--最大连接数--><property name="poolMaximumActiveConnections" value="3"/><!--这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。--><property name="poolTimeToWait" value="20000"/><!--强行回归池的时间--><property name="poolMaximumCheckoutTime" value="20000"/><!--最多空闲数量--><property name="poolMaximumIdleConnections" value="1"/></dataSource></environment></environments><mappers><mapper resource="CarMapper.xml"/></mappers>
</configuration>

poolMaximumActiveConnections:最大的活动的连接数量。默认值10 poolMaximumIdleConnections:最大的空闲连接数量。默认值5

poolMaximumCheckoutTime:强行回归池的时间。默认值20秒。

poolTimeToWait:当无法获取到空闲连接时,每隔20秒打印一次日志,避免因代码配置有误,导致傻等。(时长是可以配置的) 当然,还有其他属性。对于连接池来说,以上几个属性比较重要。

最大的活动的连接数量就是连接池连接数量的上限。默认值10,如果有10个请求正在使用这10个连接,第11个请求只能等待空闲连接。 最大的空闲连接数量。默认值5,如何已经有了5个空闲连接,当第6个连接要空闲下来的时候,连接池会选择关闭该连接对象。来减少数据库的开销。

需要根据系统的并发情况,来合理调整连接池最大连接数以及最多空闲数量。充分发挥数据库连接池的性能。【可以根据实际情况进行测试,然后调整一个合理的数量。】 下图是默认配置:

在以上配置的基础之上,可以编写java程序测试:

@Test
public void testPool() throws Exception{SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config3.xml"));for (int i = 0; i < 4; i++) {SqlSession sqlSession = sqlSessionFactory.openSession();Object selectCarByCarNum = sqlSession.selectOne("selectCarByCarNum");}
}
<select id="selectCarByCarNum" resultType="com.powernode.mybatis.pojo.Car">select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where car_num = '100'
</select>

⑶type="JNDI

NDI的方式:表示对接JNDI服务器中的连接池。这种方式给了我们可以使用第三方连接池的接口。如果想使用dbcp、c3p0、druid(德鲁伊)等,需要使用这种方式。

4.properties

mybatis提供了更加灵活的配置,连接数据库的信息可以单独写到一个属性资源文件中,假设在类的根路径下创建jdbc.properties文件,配置如下:

jdbc.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbc
jdbc.username=root
jdbc.password=abc123

properties两个属性:

resource:这个属性从类的根路径下开始加载。【常用的。】

url:从指定的url加载,假设文件放在d:/jdbc.properties,这个url可以写成:file:///d:/jdbc.properties。注意是三个斜杠哦。

注意:如果不知道mybatis-config.xml文件中标签的编写顺序的话,可以有两种方式知道它的顺序:

  • 第一种方式:查看dtd约束文件。

  • 第二种方式:通过idea的报错提示信息。【一般采用这种方式】

5.mapper

mapper标签用来指定SQL映射文件的路径,包含多种指定方式,这里先主要看其中两种: 第一种:resource,从类的根路径下开始加载【比url常用】

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

如果是这样写的话,必须保证类的根下有CarMapper.xml文件。
如果类的根路径下有一个包叫做test,CarMapper.xml如果放在test包下的话,这个配置应该是这样写:

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

第二种:url,从指定的url位置加载
假设CarMapper.xml文件放在d盘的根下,这个配置就需要这样写:

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

mapper还有其他的指定方式,后面再看!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/75461.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java语言如何用AI实现文件报告的自动质检?

文件报告的质量直接影响工作效率和决策的准确性&#xff0c;然而&#xff0c;传统的文件质检方式往往依赖人工审核&#xff0c;效率低下且容易出错。那么&#xff0c;如何利用AI技术实现文件报告的自动化质检呢&#xff1f; 问题1&#xff1a;质检的目标是什么&#xff1f; 文…

es自定义ik分词器中文词库实现热更新

基于web地址的方式实现ik分词热更新。 操作系统&#xff1a;win 11 es version&#xff1a;8.6.2 ik version&#xff1a;8.6.2 1、创建web服务&#xff0c;并提供ik查询词库接口 编写分词http url代码&#xff0c;返回自定义分词内容分词词库数据来自业务需求&#xff0c;存…

铂卡梭 智能羽翼 AI 系统:交易科技的未来引擎

突破性的 AI 交易系统 铂卡梭(Pegasus)近期推出的 InnoFeather AI System(智能羽翼 AI 系统) 代表了金融科技领域的前沿突破。这一系统集成了先进的 机器学习算法、大数据分析 和 实时市场情绪感知,旨在帮助交易者在复杂多变的市场环境中做出更精准的决策。 智能羽翼 AI 系统的…

js中判断对象是否包含某个属性(元素)

在JavaScript中&#xff0c;判断对象是否包含某个属性&#xff08;元素&#xff09;主要有以下几种方法&#xff0c;根据具体需求选择合适的方式&#xff1a; 1. 使用 in 运算符 作用&#xff1a;检查对象自身及原型链上是否存在指定属性。 示例&#xff1a; javascript cons…

Anaconda和Pycharm的区别,以及如何选择两者

目录 主要区别详细说明如何选择&#xff1f;Anaconda的使用步骤 主要区别 Anaconda 和 PyCharm 是 Python 开发中常用的两个工具&#xff0c;但它们的定位和功能完全不同。以下是它们的主要区别&#xff1a; 对比项AnacondaPyCharm类型Python 发行版 包管理工具Python 集成开…

UE小:在Unreal Engine 5中实现多层静态网格体遮挡拾取

问题描述 当需要拾取被多层静态网格体遮挡的对象时&#xff0c;若所有网格体碰撞预设为BlockAll&#xff0c;需要通过特殊配置实现穿透检测。 完整实现方案 1. 创建自定义追踪通道 进入 ​项目设置&#xff08;Project Settings&#xff09; > 碰撞&#xff08;Collision…

wireshark抓包分析数据怎么看 wireshark使用教程_wireshark怎么看

Wireshark与Sniff Master&#xff1a;网络抓包工具使用指南 网络抓包分析是开发测试和网络故障排查中不可或缺的技能。在众多抓包工具中&#xff0c;Wireshark无疑是最流行且功能强大的选择&#xff0c;而Sniff Master作为后起之秀&#xff0c;也因其简洁高效的特点受到许多专…

密码学基础——古典密码学

目录 一、定义 特点&#xff1a; 二、发展阶段 三、代换密码 1.单表代换密码 1.1恺撒密码 1.2 移位变换 1.3 仿射变换 2.多表代换密码 维吉尼亚密码 四、置换密码 栅栏密码 一、定义 古典密码学是指在现代密码学出现之前&#xff0c;使用较为简单的数学方法和手工…

【案例分享】江苏某汽车制造厂水冷式制冷站AI节能优化方案

主要诉求&#xff1a; 对B系统进行AI节能优化&#xff1a;3台离心机1台螺杆机板式换热器 优化前后对比&#xff1a; ⚫ 优化前&#xff1a;根据人工经验判断冷机和板换的启停&#xff0c;PLC固定逻辑调节参数 ⚫优化后&#xff1a;根据冷负荷对工况进行分类&#xff0c;自动…

vue+springboot 新增操作,前端id传string,后端接收为long类型,报错类型不匹配——解决方法

我在做新增功能的时候&#xff0c;做了一个逻辑判断&#xff0c;当前端没有传递对应的id值时&#xff0c;为新增&#xff1b;有id值时&#xff0c;为修改 问题一、&#xff1a;前端idundefined&#xff0c;和我的需求不符合&#xff0c;我要id为空&#xff0c;不传值。最后发现…

vue前端项目技术架构(第二版)

vue技术架构介绍 如下图所示&#xff0c;展示了项目系统的软件层次架构。该系统采用基于SOA&#xff08;面向服务架构&#xff09;思想的分层架构&#xff0c;分为四个主要层次&#xff1a;视图层、编译层、代码层和数据层。 视图层 浏览器&#xff1a;核心职责是解析并展示…

在服务器里面磁盘分区很简单吗?

不管是我们的普通办公电脑还是服务器都是需要硬盘的&#xff0c;硬盘的类型分机械硬盘&#xff08;HDD&#xff09;和固态硬盘&#xff08;SSD&#xff09;&#xff0c;这两种磁盘是我们平常最常见的硬盘您他们又有什么区别 机械硬盘&#xff08;HDD&#xff09; 原理&#xff…

Pycharm(十一):字符串练习题

1.输入一个字符串&#xff0c;打印所有偶数位上的字符(下标是0&#xff0c;2&#xff0c;4&#xff0c;6...位上的字符) # 练习题1:输入一个字符串&#xff0c;打印所有偶数位上的字符(下标是0&#xff0c;2&#xff0c;4&#xff0c;6...位上的字符) # 1.键盘录入字符串&…

虚幻5入门

常用操作 运行时&#xff0c;调试相机&#xff0c;按~键&#xff0c;输入ToggleDebugCamera 。进入自由视角 常用节点 gate节点&#xff1a;用于控制该流程通不通&#xff0c;执不执行。Flip Flop节点&#xff1a;反转执行&#xff0c;一次A&#xff0c;一次B。Set Timer by…

Prompt Flow 与 DSPy:大型语言模型开发的未来

作为一名大模型算法工程师&#xff0c;我一直在探索如何更高效地开发和优化基于大型语言模型&#xff08;LLM&#xff09;的应用程序。随着模型规模的不断扩大和应用场景的日益复杂&#xff0c;传统的开发方式已经难以满足高效、灵活和可扩展的需求。幸运的是&#xff0c;Promp…

Prompt攻击是什么

什么是Prompt攻击 Prompt攻击(Prompt Injection/Attack) 是指通过精心构造的输入提示(Prompt),诱导大语言模型(LLM)突破预设安全限制、泄露敏感信息或执行恶意操作的攻击行为。其本质是利用模型对自然语言的理解漏洞,通过语义欺骗绕过防护机制。 Prompt攻击的精髓:学…

Python 数据类型 - 集合(set)

Python 数据类型 - 集合(set) 1. 集合简介 集合(set)是Python中的一种无序、可变、不重复元素的容器数据类型。集合的主要用途&#xff1a; 快速成员检测&#xff08;判断元素是否存在&#xff09;去除重复项执行数学集合运算&#xff08;并集、交集、差集等&#xff09; 2.…

Profibus DP主站转Modbus TCP网关配置文件制作

Profibus DP主站转Modbus TCP网关配置文件制作 1、首先打开配置文件制作软件SST Profibus Configuration&#xff1a; 2、点击“Library”选择GSD文件所在文件夹找到后点击打开导入GSD文件: 3、点开Masters、molex选择主站设备&#xff1a; 4、双击添加后地址保存默认0就可以&…

如何批量拆分Excel工作表或按行拆分Excel表格 - Excel拆分器使用方法

在数据分析和处理的日常工作中&#xff0c;Excel文件因其强大的数据管理和计算能力而广受欢迎。然而&#xff0c;当面对庞大的Excel工作簿&#xff0c;特别是需要将其拆分为多个独立文件时&#xff0c;传统的操作方法往往会显得繁琐且效率低下。为了解决这一难题&#xff0c;Ex…

JavaScript基础-移动端常见特效

随着移动互联网的发展&#xff0c;为移动设备优化的网页变得越来越重要。JavaScript在实现移动端特有的交互体验中扮演着关键角色。本文将介绍几种常见的移动端特效&#xff0c;并通过具体的代码示例展示如何使用JavaScript和相关技术来创建这些特效。 一、手势识别 &#xf…