当前位置: 首页 > news >正文

MyBatis的缓存、逆向工程、使用PageHelper、使用PageHelper

一、MyBatis的缓存

缓存:cache

缓存的作用:通过减少IO的方式,来提高程序的执行效率。

mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库。一方面是减少了IO。另一方面不再执行繁琐的查找算法。效率大大提升。

mybatis缓存包括:

  • 一级缓存:将查询到的数据存储到SqlSession中。

  • 二级缓存:将查询到的数据存储到SqlSessionFactory中。

  • 或者集成其它第三方的缓存:比如EhCache【Java语言开发的】、Memcache【C语言开发的】等。

缓存只针对于DQL语句,也就是说缓存机制只对应select语句。

1.一级缓存

一级缓存默认是开启的。不需要做任何配置。

原理:只要使用同一个SqlSession对象执行同一条SQL语句,就会走缓存。

模块名:mybatis-010-cache

public interface CarMapper {/*** 根据id获取Car信息。* @param id* @return*/Car selectById(Long id);
}
<?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="org.example1.mapper.CarMapper"><select id="selectById" resultType="Car">select * from t_car where id = #{id}</select></mapper>

Test

    @Testpublic void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);Car car1 = mapper1.selectById(33L);System.out.println(car1);CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);Car car2 = mapper2.selectById(33L);System.out.println(car2);sqlSession.commit();sqlSession.close();}

什么情况下不走缓存?

  • 第一种:不同的SqlSession对象。

  • 第二种:查询条件变化了。

    @Testpublic void testSelectById() throws Exception{// 如果要获取不同的SqlSession对象,不能使用以下代码。//SqlSession sqlSession = SqlSessionUtil.openSession();SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);Car car1 = mapper1.selectById(33L);System.out.println(car1);CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);Car car2 = mapper2.selectById(33L);System.out.println(car2);sqlSession1.close();sqlSession2.close();}

一级缓存失效情况包括两种:

  • 第一种:第一次查询和第二次查询之间,手动清空了一级缓存。

sqlSession.clearCache();
  • 第二种:第一次查询和第二次查询之间,执行了增删改操作。【这个增删改和哪张表没有关系,只要有insert delete update操作,一级缓存就失效。】

    @Testpublic void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);Car car1 = mapper1.selectById(33L);System.out.println(car1);// 手动清空一级缓存sqlSession.clearCache();CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);Car car2 = mapper2.selectById(33L);System.out.println(car2);sqlSession.commit();sqlSession.close();}

CarMapper接口:写的是在t_clazz表里插入数据

package org.example1.mapper;import org.apache.ibatis.annotations.Param;
import org.example1.pojo.Car;public interface CarMapper {/*** 保存班级信息* @param cid* @param cname* @return*/int insertClazz(@Param("cid") Integer cid, @Param("cname") String cname);}
 <insert id="insertClazz">insert into t_clazz values(#{cid},#{cname})</insert>

test

    @Testpublic void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);Car car1 = mapper1.selectById(33L);System.out.println(car1);// 在这里执行了INSERT DELETE UPDATE中的任意一个语句。并且和表没有关系。CarMapper mapper = sqlSession.getMapper(CarMapper.class);mapper.insertClazz(2000, "高三三班");CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);Car car2 = mapper2.selectById(33L);System.out.println(car2);sqlSession.commit();sqlSession.close();}

2.二级缓存

二级缓存的范围是SqlSessionFactory。 使用二级缓存需要具备以下几个条件:

  1. <setting name="cacheEnabled" value="true"> 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。默认就是true,无需设置。

  2. 在需要使用二级缓存的SqlMapper.xml文件中添加配置:<cache />

  3. 使用二级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接口

  4. SqlSession对象关闭或提交之后,一级缓存中的数据才会被写入到二级缓存当中。此时二级缓存才可用。

测试二级缓存:

<cache/>
public class Car implements Serializable {
//......
}
    @Testpublic void testSelectById2() throws Exception{// 这里只有一个SqlSessionFactory对象。二级缓存对应的就是SqlSessionFactory。SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);// 这行代码执行结束之后,实际上数据是缓存到一级缓存当中了。(sqlSession1是一级缓存。)Car car1 = mapper1.selectById2(33L);System.out.println(car1);// 如果这里不关闭SqlSession1对象的话,二级缓存中还是没有数据的。// 这行代码执行结束之后,实际上数据会缓存到一级缓存当中。(sqlSession2是一级缓存。)Car car2 = mapper2.selectById2(33L);System.out.println(car2);// 程序执行到这里的时候,会将sqlSession1这个一级缓存中的数据写入到二级缓存当中。sqlSession1.close();// 程序执行到这里的时候,会将sqlSession2这个一级缓存中的数据写入到二级缓存当中。sqlSession2.close();}

把sqlSession1的一级缓存中的数据会放到二级缓存当中

    @Testpublic void testSelectById2() throws Exception{// 这里只有一个SqlSessionFactory对象。二级缓存对应的就是SqlSessionFactory。SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);// 这行代码执行结束之后,实际上数据是缓存到一级缓存当中了。(sqlSession1是一级缓存。)Car car1 = mapper1.selectById2(33L);System.out.println(car1);// 如果这里不关闭SqlSession1对象的话,二级缓存中还是没有数据的。// 如果执行了这行代码,sqlSession1的一级缓存中的数据会放到二级缓存当中。sqlSession1.close();// 这行代码执行结束之后,实际上数据会缓存到一级缓存当中。(sqlSession2是一级缓存。)Car car2 = mapper2.selectById2(33L);System.out.println(car2);// 程序执行到这里的时候,会将sqlSession1这个一级缓存中的数据写入到二级缓存当中。//sqlSession1.close();// 程序执行到这里的时候,会将sqlSession2这个一级缓存中的数据写入到二级缓存当中。sqlSession2.close();}

二级缓存的失效:只要两次查询之间出现了增删改操作。二级缓存就会失效。【一级缓存也会失效】

二级缓存的相关配置:

  1. eviction:指定从缓存中移除某个对象的淘汰算法。默认采用LRU策略。

    1. LRU:Least Recently Used。最近最少使用。优先淘汰在间隔时间内使用频率最低的对象。(其实还有一种淘汰算法LFU,最不常用。)

    2. FIFO:First In First Out。一种先进先出的数据缓存器。先进入二级缓存的对象最先被淘汰。

    3. SOFT:软引用。淘汰软引用指向的对象。具体算法和JVM的垃圾回收算法有关。

    4. WEAK:弱引用。淘汰弱引用指向的对象。具体算法和JVM的垃圾回收算法有关。

  2. flushInterval:

    1. 二级缓存的刷新时间间隔。单位毫秒。如果没有设置。就代表不刷新缓存,只要内存足够大,一直会向二级缓存中缓存数据。除非执行了增删改。

  3. readOnly:

    1. true:多条相同的sql语句执行之后返回的对象是共享的同一个。性能好。但是多线程并发可能会存在安全问题。

    2. false:多条相同的sql语句执行之后返回的对象是副本,调用了clone方法。性能一般。但安全。

  4. size:

    1. 设置二级缓存中最多可存储的java对象数量。默认值1024。

3.MyBatis集成EhCache

集成EhCache是为了代替mybatis自带的二级缓存。一级缓存是无法替代的。

mybatis对外提供了接口,也可以集成第三方的缓存组件。比如EhCache、Memcache等。都可以。

EhCache是Java写的。Memcache是C语言写的。所以mybatis集成EhCache较为常见,按照以下步骤操作,就可以完成集成:

第一步:引入mybatis整合ehcache的依赖。

<!--mybatis集成ehcache的组件-->
<dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.2.2</version>
</dependency>

第二步:在类的根路径下新建echcache.xml文件,并提供以下配置信息。

<?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"><!--磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存--><diskStore path="e:/ehcache"/><!--defaultCache:默认的管理策略--><!--eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断--><!--maxElementsInMemory:在内存中缓存的element的最大数目--><!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上--><!--diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false--><!--timeToIdleSeconds:对象空闲时间(单位:秒),指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问--><!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问--><!--memoryStoreEvictionPolicy:缓存的3 种清空策略--><!--FIFO:first in first out (先进先出)--><!--LFU:Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存--><!--LRU:Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存--><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"/>
    @Testpublic void testSelectById2() throws Exception{// 这里只有一个SqlSessionFactory对象。二级缓存对应的就是SqlSessionFactory。SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);// 这行代码执行结束之后,实际上数据是缓存到一级缓存当中了。(sqlSession1是一级缓存。)Car car1 = mapper1.selectById2(33L);System.out.println(car1);// 如果这里不关闭SqlSession1对象的话,二级缓存中还是没有数据的。// 如果执行了这行代码,sqlSession1的一级缓存中的数据会放到二级缓存当中。sqlSession1.close();// 这行代码执行结束之后,实际上数据会缓存到一级缓存当中。(sqlSession2是一级缓存。)Car car2 = mapper2.selectById2(33L);System.out.println(car2);// 程序执行到这里的时候,会将sqlSession1这个一级缓存中的数据写入到二级缓存当中。//sqlSession1.close();// 程序执行到这里的时候,会将sqlSession2这个一级缓存中的数据写入到二级缓存当中。sqlSession2.close();}

二、MyBatis的逆向工程

所谓的逆向工程是:根据数据库表逆向生成Java的pojo类,SqlMapper.xml文件,以及Mapper接口类等。

要完成这个工作,需要借助别人写好的逆向工程插件。

思考:使用这个插件的话,需要给这个插件配置哪些信息?

  • pojo类名、包名以及生成位置。

  • SqlMapper.xml文件名以及生成位置。

  • Mapper接口名以及生成位置。

  • 连接数据库的信息。

  • 指定哪些表参与逆向工程。

  • ......

1.逆向工程配置与生成

第一步:基础环境准备

新建模块:mybatis-011-generator 打包方式:jar

第二步:在pom中添加逆向工程插件

<!--定制构建过程-->
<build><!--可配置多个插件--><plugins><!--其中的一个插件:mybatis逆向工程插件--><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

该文件名必须叫做:generatorConfig.xml 该文件必须放在类的根路径下。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!--targetRuntime有两个值:MyBatis3Simple:生成的是基础版,只有基本的增删改查。MyBatis3:生成的是增强版,除了基本的增删改查之外还有复杂的增删改查。--><context id="DB2Tables" targetRuntime="MyBatis3Simple"><!--防止生成重复代码--><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/jdbc"userId="root"password="abc123"></jdbcConnection><!-- 生成pojo包名和位置 --><javaModelGenerator targetPackage="org.example1.pojo" targetProject="src/main/java"><!--是否开启子包--><property name="enableSubPackages" value="true"/><!--是否去除字段名的前后空白--><property name="trimStrings" value="true"/></javaModelGenerator><!-- 生成SQL映射文件的包名和位置 --><sqlMapGenerator targetPackage="org.example1.mapper" targetProject="src/main/resources"><!--是否开启子包--><property name="enableSubPackages" value="true"/></sqlMapGenerator><!-- 生成Mapper接口的包名和位置 --><javaClientGeneratortype="xmlMapper"targetPackage="org.example1.mapper"targetProject="src/main/java"><property name="enableSubPackages" value="true"/></javaClientGenerator><!-- 表名和对应的实体类名--><table tableName="t_car" domainObjectName="Car"/></context>
</generatorConfiguration>

第四步:运行插件

2.测试逆向工程生成的是否好用

第一步:环境准备

  • 依赖:mybatis依赖、mysql驱动依赖、junit依赖、logback依赖

  • jdbc.properties

  • mybatis-config.xml

  • logback.xml

第二步:编写测试程序

    @Testpublic void testSelectAll(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectAll();cars.forEach(car -> System.out.println(car));sqlSession.close();}@Testpublic void testDeleteByPrimaryKey(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);int count = mapper.deleteByPrimaryKey(33L);System.out.println(count);sqlSession.commit();sqlSession.close();}

    // CarExample类负责封装查询条件的。@Testpublic void testSelect(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);// 执行查询// 1. 查询一个Car car = mapper.selectByPrimaryKey(32L);System.out.println(car);// 2. 查询所有(selectByExample,根据条件查询,如果条件是null表示没有条件。)List<Car> cars = mapper.selectByExample(null);cars.forEach(car1 -> System.out.println(car1));System.out.println("=========================================");// 3. 按照条件进行查询// QBC 风格:Query By Criteria 一种查询方式,比较面向对象,看不到sql语句。// 封装条件,通过CarExample对象来封装查询条件//把where后面的条件封装起来CarExample carExample = new CarExample();// 调用carExample.createCriteria()方法来创建查询条件carExample.createCriteria().andBrandLike("帕萨特").andGuidePriceGreaterThan(new BigDecimal(20.0));// 添加orcarExample.or().andCarTypeEqualTo("燃油车");// 执行查询List<Car> cars2 = mapper.selectByExample(carExample);cars2.forEach(car2 -> System.out.println(car2));sqlSession.close();}

三、MyBatis使用PageHelper

1.limit分页

mysql的limit后面两个数字:

  • 第一个数字:startIndex(起始下标。下标从0开始。)

  • 第二个数字:pageSize(每页显示的记录条数)

假设已知页码pageNum,还有每页显示的记录条数pageSize,第一个数字可以动态的获取吗?

  • startIndex = (pageNum - 1) * pageSize

所以,标准通用的mysql分页SQL:

select * 
from tableName ...... 
limit (pageNum - 1) * pageSize, pageSize

使用mybatis应该怎么做?

模块名:mybatis-012-page

package org.example1.mapper;import org.apache.ibatis.annotations.Param;
import org.example1.pojo.Car;import java.util.List;public interface CarMapper {/*** 分页查询* @param startIndex 起始下标。* @param pageSize 每页显示的记录条数* @return*/List<Car> selectByPage(@Param("startIndex") int startIndex, @Param("pageSize") int pageSize);
}
    <select id="selectByPage" resultType="Car">select * from t_car limit #{startIndex},#{pageSize}</select>
    @Testpublic void testSelectByPage(){// 获取每页显示的记录条数int pageSize = 3;// 显示第几页:页码int pageNum = 2;// 计算开始下标int startIndex = (pageNum - 1) * pageSize;SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectByPage(startIndex, pageSize);cars.forEach(car -> System.out.println(car));sqlSession.close();}

2.PageHelper插件

使用PageHelper插件进行分页,更加的便捷。

第一步:引入依赖

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

第二步:在mybatis-config.xml文件中配置插件

typeAliases标签下面进行配置:

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

第三步:编写Java代码

package org.example1.mapper;import org.apache.ibatis.annotations.Param;
import org.example1.pojo.Car;import java.util.List;public interface CarMapper {/*** 查询所有的Car,通过分页查询插件PageHelper完成。* @return*/List<Car> selectAll();
    <select id="selectAll" resultType="Car">select * from t_car</select>
    @Testpublic 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();cars.forEach(car -> System.out.println(car));// 封装分页信息对象new PageInfo()// PageInfo对象是PageHelper插件提供的,用来封装分页相关的信息的对象。PageInfo<Car> carPageInfo = new PageInfo<>(cars, 3);System.out.println(carPageInfo);sqlSession.close();/*PageInfo{pageNum=2, pageSize=3, size=3, startRow=4, endRow=6, total=7, pages=3,list=Page{count=true, pageNum=2, pageSize=3, startRow=3, endRow=6, total=7, pages=3, reasonable=false, pageSizeZero=false}[Car{id=168, carNum='1204', brand='奥迪Q7', guidePrice=3.0, produceTime='2009-10-11', carType='燃油车'},Car{id=169, carNum='1205', brand='朗逸', guidePrice=4.0, produceTime='2001-10-11', carType='新能源'},Car{id=170, carNum='1206', brand='奔驰E300L', guidePrice=50.0, produceTime='2003-02-03', carType='新能源'}],prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true,navigatePages=3, navigateFirstPage=1, navigateLastPage=3, navigatepageNums=[1, 2, 3]}*/}

分页信息

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, hasPreviousPage=true, hasNextPage=true, navigatePages=5, navigateFirstPage=1, navigateLastPage=3, navigatepageNums=[1, 2, 3]
}

四、MyBatis的注解式开发

mybatis中也提供了注解式开发方式,采用注解可以减少Sql映射文件的配置。

当然,使用注解式开发的话,sql语句是写在java程序中的,这种方式也会给sql语句的维护带来成本。 官方是这么说的:

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。

使用注解编写复杂的SQL是这样的:

原则:简单sql可以注解。复杂sql使用xml。

模块名:mybatis-013-annotation

打包方式:jar

依赖:mybatis,mysql驱动,junit,logback

配置文件:jdbc.properties、mybatis-config.xml、logback.xml

pojo:org.example1.pojo.Car

mapper接口:org.example1.mapper.CarMapper

1. @Insert

package org.example1.mapper;import org.apache.ibatis.annotations.*;
import org.example1.pojo.Car;public interface CarMapper {@Insert("insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})")int insert(Car car);}
    @Testpublic void testInsert(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = new Car(null,"6666","丰田霸道",32.0,"2020-11-11","燃油车");int count = mapper.insert(car);System.out.println(count);sqlSession.commit();sqlSession.close();}

2.@Delete

package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.*;public interface CarMapper {@Delete("delete from t_car where id = #{id}")int deleteById(Long id);
}
   @Testpublic void testDeleteById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);int count = mapper.deleteById(31L);System.out.println(count);sqlSession.commit();sqlSession.close();}

3.

3.@Update

package org.example1.mapper;import org.apache.ibatis.annotations.*;
import org.example1.pojo.Car;public interface CarMapper {@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);
    @Testpublic void testUpdate(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = new Car(17L,"6666","丰田霸道",32.0,"2020-11-11","燃油车");int count = mapper.update(car);System.out.println(count);sqlSession.commit();sqlSession.close();}

4.@Select

package org.example1.mapper;import org.apache.ibatis.annotations.*;
import org.example1.pojo.Car;public interface CarMapper {@Select("select * from t_car where id = #{id}")Car selectById(Long id);
    @Testpublic void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = mapper.selectById(17L);System.out.println(car);sqlSession.close();}

    @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(Long id);

相关文章:

MyBatis的缓存、逆向工程、使用PageHelper、使用PageHelper

一、MyBatis的缓存 缓存&#xff1a;cache 缓存的作用&#xff1a;通过减少IO的方式&#xff0c;来提高程序的执行效率。 mybatis的缓存&#xff1a;将select语句的查询结果放到缓存&#xff08;内存&#xff09;当中&#xff0c;下一次还是这条select语句的话&#xff0c;直…...

GS+:地统计分析与空间插值工具

大家好&#xff0c;今天为大家介绍的软件是GS&#xff1a;一款用于地统计分析与空间数据处理的软件。与ArcGIS相比的话&#xff0c;它更适合专注于地质统计学分析的用户&#xff0c;尤其是需要对半方差函数进行深入分析和调整的场景下面。我们将从软件的主要功能、支持的系统、…...

C++类型转换详解

目录 一、内置 转 内置 二、内置 转 自定义 三、自定义 转 内置 四、自定义 转 自定义 五、类型转换规范化 1.static_case 2.reinterpret_cast 3.const_cast 4.dynamic_cast 六、RTTI 一、内置 转 内置 C兼容C语言&#xff0c;在内置类型之间转换规则和C语言一样的&am…...

scala-集合2

可变数组 定义变长数组 val arr01 ArrayBuffer[Any](3, 2, 5) &#xff08;1&#xff09;[Any]存放任意数据类型 &#xff08;2&#xff09;(3, 2, 5)初始化好的三个元素 &#xff08;3&#xff09;ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer 案例实操 Arra…...

Clang编译器优化选项

Clang 作为 C/C 编译器&#xff0c;提供了丰富的优化选项&#xff0c;以下是主要的优化相关选项分类和说明&#xff1a; 1. 优化级别&#xff08;通用选项&#xff09; 选项说明-O0默认级别&#xff0c;禁用所有优化&#xff0c;用于调试。-O1基础优化&#xff08;代码大小和执…...

Java文件流操作 - 【Guava】IO工具

引言 Guava 使用术语 流来表示可关闭的&#xff0c;并且在底层资源中有位置状态的 I/O 数据流。字节流对应的工具类为 ByteSterams&#xff0c;字符流对应的工具类为 CharStreams。 Guava 中为了避免和流直接打交道&#xff0c;抽象出可读的 源 source 和可写的 汇 sink 两个概…...

C语言中单链表操作:查找节点与删除节点

一. 简介 前面学习了C语言中创建链表节点&#xff0c;向链表中插入节点等操作&#xff0c;文章如下&#xff1a; C语言中单向链表&#xff1a;创建节点与插入新节点-CSDN博客 本文继续学习c语言中对链表的其他操作&#xff0c;例如在链表中查找某个节点&#xff0c;删除链表…...

mapbox基础,加载栅格图片到地图

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️raster 栅格图层 api二、🍀使用本地载…...

Linux红帽:RHCSA认证知识讲解(十 二)调试 SELinux,如何管理 SELinux 的运行模式、安全策略、端口和上下文策略

Linux红帽&#xff1a;RHCSA认证知识讲解&#xff08;十 二&#xff09;调试 SELinux&#xff0c;如何管理 SELinux 的运行模式、安全策略、端口和上下文策略 前言一、SELinux 简介二、SELinux 的运行模式2.1 查看和切换 SELinux 模式 三、SELinux 预设安全策略的开关控制四、管…...

模糊斜率熵Fuzzy Slope entropy+状态分类识别!2024年11月新作登上IEEE Trans顶刊

引言 2024年11月&#xff0c;研究者在测量领域国际顶级期刊《IEEE Transactions on Instrumentation and Measurement》&#xff08;IF 5.6&#xff0c;JCR 1区&#xff0c;中科院二区&#xff09;上发表科学研究成果&#xff0c;以“Optimized Fuzzy Slope Entropy: A Comple…...

【MATLAB】将数据保存在mat文件中 save/load/matfile

MAT文件为MATLAB格式的二进制文件 save()函数 save - 将工作区变量保存到文件中 save(filename) 将当前工作区中的所有变量保存在 MATLAB 格式的二进制文件&#xff08;MAT 文件&#xff09;filename 中。如果 filename 已存在&#xff0c;save 会覆盖该文件。 save(filena…...

009_抽象类和接口

抽象类和接口 final关键字常量 单例模式&#xff08;设计模式&#xff09;枚举类抽象类抽象类的注意事项、特点使用抽象类的好处模版方法设计模式 接口接口的好处接口的注意事项 final关键字 final关键字是最终的意思&#xff0c;可以修饰类、方法、变量。 修饰类&#xff1a;…...

【数据结构】排序算法(下篇·开端)·深剖数据难点

前引&#xff1a;前面我们通过层层学习&#xff0c;也就了解了Hoare大佬的排序思想&#xff0c;今天我们学习的东西可能稍微有点难度&#xff0c;因此我们必须学会思想&#xff0c;我很受感慨&#xff0c;因此借此分享一下&#xff1a;【用1520分钟去调试】&#xff0c;如果我们…...

Elixir语言的计算机视觉

Elixir语言在计算机视觉中的应用 引言 计算机视觉作为一门交叉学科&#xff0c;近年来随着深度学习技术的发展而蓬勃发展。传统上&#xff0c;计算机视觉应用通常采用Python、C等语言进行开发&#xff0c;因为这些语言拥有强大的图像处理库和深度学习框架。然而&#xff0c;随…...

VTK知识学习(51)- 交互与Widget(二)

1、交互器样式 前面所讲的观察者/命令模式是 VTK实现交互的方式之一。在前面示例 所示的窗口中可以使用鼠标与柱体进行交互&#xff0c;比如用鼠标滚轮可以对柱体放大、缩小;按下鼠标左键不放&#xff0c;然后移动鼠标&#xff0c;可以转动柱体;按下鼠标左键&#xff0c;同时按…...

目标跟踪Deepsort算法学习2025.4.7

一.DeepSORT概述 1.1 算法定义 DeepSORT(Deep Learning and Sorting)是一种先进的多目标跟踪算法,它结合了深度学习和传统的目标跟踪技术,在复杂环境下实现了高精度和鲁棒性的目标跟踪。该算法的核心思想是通过融合目标的外观特征和运动特征,实现对多个目标的持续跟踪,…...

nacos集群启动问题

根据您的描述&#xff0c;Nacos集群只能启动两个节点&#xff0c;可能的原因和解决方法如下&#xff1a; 1. 集群配置问题 • 原因&#xff1a;cluster.conf文件中可能只配置了两个节点的地址&#xff0c;导致第三个节点无法加入集群。 • 解决方法&#xff1a; • 检查每个…...

八大排序——c++版

本次排序都是按照升序排的 冒泡排序 void bubbleSort(vector<int>& nums) {int nnums.size();for(int i0;i<n-1;i){bool swappedfalse;for(int j0;j<n-1-i;j){if(nums[j]>nums[j1]){swap(nums[j],nums[j1]);swappedtrue;}}if(!swapped)break;} } //算法原…...

关于Spring MVC中传递数组参数的详细说明,包括如何通过逗号分隔的字符串自动转换为数组,以及具体的代码示例和总结表格

以下是关于Spring MVC中传递数组参数的详细说明&#xff0c;包括如何通过逗号分隔的字符串自动转换为数组&#xff0c;以及具体的代码示例和总结表格&#xff1a; 1. 核心机制 Spring MVC支持直接通过逗号分隔的字符串将请求参数自动转换为数组&#xff08;String[]、int[]等&…...

VBA之Word应用:利用Range方法进行字体及对齐方式设置

《VBA之Word应用》&#xff08;版权10178982&#xff09;&#xff0c;是我推出第八套教程&#xff0c;教程是专门讲解VBA在Word中的应用&#xff0c;围绕“面向对象编程”讲解&#xff0c;首先让大家认识Word中VBA的对象&#xff0c;以及对象的属性、方法&#xff0c;然后通过实…...

区块链技术:重塑供应链管理的未来

在当今全球化的商业环境中&#xff0c;供应链管理的复杂性和重要性日益凸显。从原材料采购到产品交付&#xff0c;供应链的每一个环节都可能影响企业的运营效率和客户满意度。随着区块链技术的兴起&#xff0c;供应链管理迎来了新的变革机遇。本文将深入探讨区块链技术在供应链…...

请回答集成测试和系统测试的区别,以及它们的应用场景主要是什么?

导语: 深夜收到粉丝私信:"面了5家大厂,4家都问集成测试和系统测试的区别,求大佬支招!" 作为经历过200+项目实战的测试老司机,今天用4个真实项目案例+3张原理图,带你彻底吃透这两个核心测试阶段!(文末送测试用例模板) 一、灵魂三问:到底测什么? 1.1 集成…...

SVT-AV1学习-svt_aom_get_sg_filter_level,svt_av1_selfguided_restoration_c

SVT-AV1学习-svt_aom_get_sg_filter_level,svt_av1_selfguided_restoration_c 一 函数的作用 根据编码模式&#xff0c;输入分辨率和快速解码标志动态计算自引导恢复(Self Guide Restoration)过滤器的启动级别&#xff0c;以下是详细解析&#xff1b; 1 参数说明 EncMode enc_m…...

第七章总结:集合

一、集合简介 Scala集合分为三大类&#xff1a;序列&#xff08;Seq&#xff09;、集&#xff08;Set&#xff09;、映射&#xff08;Map&#xff09;&#xff0c;所有集合都扩展自Iterable特质。集合分为可变集合和不可变集合&#xff1a; 不可变集合&#xff1a;scala.collec…...

玄机靶场:apache日志分析

什么是Apache日志 Apache日志‌是Apache Web服务器在处理HTTP请求时记录的所有事件的详细信息。Apache是全球最受欢迎的Web服务器软件之一&#xff0c;支持约30.2%的所有活跃网站。Apache通过记录每次请求的信息&#xff0c;包括时间、来源IP、请求的资源等&#xff0c;帮助分…...

Laravel 使用 事件和监听器实现 数据状态变更

首先知道事件是什么 1.事件的概念 事件(Event)是 Laravel 中实现观察者模式的一种机制&#xff0c;它允许应用程序中的不同部分进行松耦合的通信。 通俗一点就是&#xff0c;发生在应用程序中的动作或者事情。例如&#xff1a; 用户注册成功后&#xff0c;需要发邮件&#…...

uniapp App页面通过 web-view 调用网页内方法

先是报这个错 A parser-blocking, cross site (i.e. different eTLD1) script, https://api.map.baidu.com/getscript?v3.0&akpgJsRF87Fjia&services&t20250225111334, is invoked via document.write. The network request for this script MAY be blocked by t…...

Daz3D角色UE5材质优化

解决Daz3D人物角色导入UE5后材质不真实的问题 1. 引言&#xff1a;跨平台3D资产传输中的材质保真度挑战 在当今的数字内容创作领域&#xff0c;对高质量3D人物角色的需求日益增长&#xff0c;广泛应用于游戏开发、电影制作、虚拟现实等多种应用场景。Daz3D因其丰富的人物模型…...

Android studio

问题&#xff1a;没有界面可以操作&#xff0c;页面没有hello wolrd 原因&#xff1a;gradle没同步完&#xff0c;依赖项没有下载完整&#xff0c;所以布局预览看不了...

Playwright快照测试:如何让UI回归测试变得轻松高效

引言 使用带有模拟数据的PlaywrightP快照可以显著提高UI回归测试的速度。它能够快速自动化检查三大主流浏览器&#xff08;Chromium、Firefox、Webkit&#xff09;中的 UI 元素。你可以将多个断言绑定到一个快照上&#xff0c;这极大地提高了 UI 测试的效率。在 GUI 应用快速扩…...

控制理论-传递函数

【硬核】终于有人把传递函数和卷积定理讲明白了&#xff01;自动控制原理入门-传递函数 | 卷积定理 | 频率响应 | 喵星考拉...

虚拟世界的AI魔法:AIGC引领元宇宙创作革命

云边有个稻草人-CSDN博客——个人主页 热门文章_云边有个稻草人的博客-CSDN博客——本篇文章所属专栏 ~ 欢迎订阅~ 目录 1. 引言 2. 元宇宙与虚拟世界概述 2.1 什么是元宇宙&#xff1f; 2.2 虚拟世界的构建 3. AIGC在元宇宙中的应用 3.1 AIGC生成虚拟世界环境 3.2 AIGC…...

带QT界面的文件管理系统

下载地址 下载&完整介绍地址&#xff1a;https://www.mcso.top/course-design/qt-filesystem/ 开源地址&#xff1a;https://github.com/mcdudu233/FileSystem.git 软件包含 &#xff08;1&#xff09;设计数据的结构 &#xff08;2&#xff09;设计文件管理系统 &…...

【区块链安全 | 第二十六篇】表达式与控制结构(二)

文章目录 表达式与控制结构赋值结构化赋值与返回多个值数组和结构体的赋值复杂性作用域和声明检查或不检查的算术运算错误处理:Assert、Require、Revert 和异常通过 assert 进行 Panic 和通过 require 进行 Errorreverttry/catch表达式与控制结构 赋值 结构化赋值与返回多个…...

2025年前端框架全景解析:React、Vue、Angular的生态与未来之争

一、市场格局:全球与国内的双重差异12 全球市场React:凭借Facebook的支持和庞大的社区,全球使用率超40%,尤其在数据密集型应用(如金融、社交平台)中占据主导。其跨平台能力(React Native)和灵活生态(Next.js、Redux)是核心竞争力。Vue:亚洲市场占比显著,中国开发者…...

【VScode】C/C++使用教程

编辑器 1. VScode本质上是一款代码编辑器&#xff0c;上面包含了许多插件。 VScode下载 1. 下载链接&#xff1a;Download Visual Studio Code - Mac, Linux, Windowshttps://code.visualstudio.com/download2. 在拓展部分下载汉化包&#xff1a;Chinese。 编译器 1. 我们使用M…...

【Node】如何使用PM2高效部署nodejs前端应用

引言 Node.js 这个服务端 JavaScript 运行时&#xff0c;能帮你打造高性能的实时 Web 和移动应用。不过相比传统的 Apache 或 Nginx 这类 Web 服务器&#xff0c;Node 应用的管理可要多花点心思。 PM2 就是专为生产环境设计的 Node 应用进程管理系统。这篇指南将手把手教你安…...

从零开始的图论讲解(1)——图的概念,图的存储,图的遍历与图的拓扑排序

目录 前言 图的概念 1. 顶点和边 2. 图的分类 3. 图的基本性质 图的存储 邻接矩阵存图 邻接表存图 图的基本遍历 拓扑排序 拓扑排序是如何写的呢? 1. 统计每个节点的入度 2. 构建邻接表 3. 将所有入度为 0 的节点加入队列 4. 不断弹出队头节点&#xff0c;更新其…...

无人机双频技术及底层应用分析!

一、双频技术的核心要点 1. 频段特性互补 2.4GHz&#xff1a;穿透力强、传输距离远&#xff08;可达5公里以上&#xff09;&#xff0c;适合复杂环境&#xff08;如城市、建筑物密集区&#xff09;&#xff0c;但易受Wi-Fi、蓝牙等设备的干扰。 5.8GHz&#xff1a;带宽更…...

基础知识补充篇:认识区块链浏览器

专栏:区块链入门到放弃查看目录-CSDN博客文章浏览阅读218次。为了方便查看将本专栏的所有内容列出目录,按照顺序查看即可。https://blog.csdn.net/qq_22502303/article/details/147022618?spm=1001.2014.3001.5501 前言 在《基础知识补充篇:什么是区块链RPC节点》文中笔者…...

git rebase复杂场景验证

经常面临复杂的分支管理&#xff0c;这里对几种场景的行为做一些验证。 结论总结 git rebase br_name&#xff1a;等价与新建br_name分支&#xff0c;然后找到当前分支与br_name分支的分叉点。然后把分叉点以后的提交&#xff08;当前分支&#xff09;一个一个的cherry-pick过…...

安宝特应用 | 工业AR技术赋能高端制造领域验收流程数字化转型

引言 随着高端制造行业对效率与安全要求的不断提升&#xff0c;传统验收模式正迎来智能化升级。针对特殊行业产品验收过程中存在的跨区域协作难、人工核验效率低等痛点&#xff0c;基于AR增强现实技术的智能验收方案正在成为转型新方向。 01 可视化协同提升验收效能 安宝特AR…...

Spring启示录、概述、入门程序以及Spring对IoC的实现

一、Spring启示录 阅读以下代码&#xff1a; dao package org.example1.dao;/*** 持久层* className UserDao* since 1.0**/ public interface UserDao {/*** 根据id删除用户信息*/void deleteById(); } package org.example1.dao.impl;import org.example1.dao.UserDao;/**…...

Oracle 23ai Vector Search 系列之4 VECTOR数据类型和基本操作

文章目录 Oracle 23ai Vector Search 系列之4 VECTOR数据类型和基本操作VECTOR 数据类型基本语法Vector 维度限制和向量大小向量存储格式&#xff08;DENSE vs SPARSE&#xff09;1. DENSE存储2. SPARSE存储3. 内部存储与空间计算 Oracle VECTOR数据类型的声明格式VECTOR基本操…...

如何用开源工具,把“定制动漫面具”做成柔性制造?

原文链接&#xff1a;https://www.nocobase.com/cn/blog/kigland。 引言 在苏州&#xff0c;有一支团队正在悄悄改变个性化制造的方式。他们不做快消品&#xff0c;也不靠规模取胜&#xff0c;却在全球角色扮演爱好者圈子里收获了不少“忠粉”。 他们叫 KIGLAND&#xff0c;一…...

《命理学》专项探究与研习

基础论调 八字是什么 八字&#xff1a;用天干地支表示一个人的出生时间 例如&#xff1a; 如上图&#xff1a;某人的干支历出生时间&#xff1a;甲申年--己巳月--戊戌日--癸丑时 十天干 甲乙丙丁戊己庚辛壬癸 奇数位为阳&#xff0c;偶数位为阴 十二地支 子丑寅卯辰巳午未申酉…...

Linux 指令初探:开启终端世界的大门

前言 当我们初次接触 Linux&#xff0c;往往会被一串串在黑底屏幕中跳动的字符震撼甚至吓退。然而&#xff0c;正是这些看似晦涩的命令&#xff0c;构建了服务器、嵌入式系统乃至云计算的世界。 本篇将带你从最基础的 Linux 指令开始&#xff0c;逐步揭开命令行的神秘面纱。从…...

CentOS 7 yum 无法安装软件的解决方法

一、解决方法 1、备份原有的 CentOS 7 默认 YUM 源配置文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup2、从阿里云镜像源下载 CentOS 7 的 YUM 源配置文件&#xff0c;并覆盖原有的配置文件 wget -O /etc/yum.repos.d/CentOS-Base.re…...

oracle 游标的管理

8.2.1游标的概念和类型 游标(CURSOR)存储于服务器端&#xff0c;当服务器执行了一个查询后&#xff0c;查询返回的记录集存放在光标中&#xff0c;通过光标上的操作可以把这些记录检索到客户端的应用程序。光标是一种变量&#xff0c;它对应于一个查询语句确定的结果集。它用于…...

深入理解PCA降维:原理、实现与应用

1. 引言 在机器学习与数据科学领域&#xff0c;我们经常会遇到高维数据带来的"维度灾难"问题。随着特征数量的增加&#xff0c;数据稀疏性、计算复杂度等问题会显著加剧。主成分分析(PCA, Principal Component Analysis)作为一种经典的降维技术&#xff0c;能够有效解…...