MyBatis

MyBatis入门

用来替代JDBC来访问数据库

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录

MyBatis 是支持普通 SQL查询,存储过程]和高级映射的优秀持久层框架MyBatis 消除了几乎所有的JDBCC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。

MyBatis是一个半自动的ORM框架,其本质是对JDBC的封装

使用MyBatis需要程序员编写SQL命令,不需要写一行JDBC代码

1.持久层(Persistence Layer)

​ 数据访问层又称为DAL层(Data Access Layer),有时候也称为是持久层,其功能主要是负责数据库的访问

​ 持久层( Persistence Layer) , 即专注于实现数据持久化应用领域的某个特定系统的个逻辑层面,将数据使用者和数据实 体相关联。之前使用JDBC访问数据库的DAO层,
​ 后面采用MyBatis访问数据库的mapper层,就是持久层

2.什么是框架(Framwrok)

​ 是一框子—— 指其约束性(采用一种框架其实就是限制用户必须使用其规定方安来实

​ 现),

​ 也是一个架子——指其支撑性

​ 是一个基本概念上的结构,用于解决或复杂的问题

​ 框架( Framework )是构成一类特定软件可复用设计的一组相互协作的类

​ 框架规定了你的应用的体系结构。它定义了整体结构,类和对象的分割,

​ 各部分的主要责任,类和对象怎么协作,以及控制流程。框架预定义了

​ 这些设计参数,以便于应用设计者或实现者能集中精力于应用本身的特定细节

​ 框架是一个半成品,对基础的代码进行封装并提供相应的API,开发者使用框架直接调用封装

​ 好的API可以省去很多代码编写时间,从而提高工作效率和开发速度

​ 对于java来说,就是一系列为了解决特定问题而定义的一系列接口和实现类,在组织框架代码时,使用了一系列优秀的设计模式,使代码无论在性能上还是API操作上得到很大提升.框架可以看做是项目开发的半成品,基本的底层操作已经封装完毕,通过框架,程序员可以从底层代码中解脱出来,专注于业务逻辑的完成和性能的优化

2.1.使用框架的好处

​ 框架的最大好处是重用

​ 减少开发时间

​ 降低开发难度

​ 保证设计质量

​ 降低维护成本

2.2 .常用的基于JavaEE的三大开源框架

​ Spring、 SpringMVC、 Mybatis

3.什么是ORM(Object Relational Mapping)

​ JDBC的缺点:需要手动的完成面向对象的Java语言、面向关系数据库之间的转换,

​ 代码繁琐无技术含量,影响代码开发效率。

​ 需要手动的将结果集的列数转换为Java对象的属性转换为数据库的列字段

对象关系映射(Object Relational Mapping)简称ORM

   作用:在关系型数据库和对象之间做一个映射,操作数据数据库的时候

​ 只要象操作对象一样操作它就可以了,ORM框架会根据映射完成

​ 数据映射完成数据库的相关操作,不用再去和复杂的SQL语句打交道了。

4.持久化(Persistence)

​ 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。

​ 持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。

5.MyBatis和Hibernate比较

​ Hibernate是一个全自动ORM框架。Hibernate创建了Java对象和数据之间的完整映射,可以完全以面象

​ 对象的思想来操作数据库,程序员不需要手写SQL语句。

​ MyBatis是一个半自动的ORM框架,MyBatis需要手写SQL语句,所以工作量大于Hibernate。

5.1 为什么半自动化的Mybatis比全自动的Hibernate受欢迎

​ MyBatis需要手写SQL语句,所以工作量大于Hibernate。

​ 但正是因为可以自定义SQL语句,所以其灵活性,可优化就超越了Hibernate。

Hibernate封装了SQL语句,由开发者对对象操作。虽然可以通过映射配置来控制生成SQL语句,

​ 但是要生成复杂的SQL语句,很难实现,或者实现后导致性能丢失

​ 而MyBatis将手写SQL语句的工作丢给开发者,可以更精确的定义SQL,更加灵活,以便于优化性能

​ 完成同样功能的两条SQL语句性能可能相差十几倍到几十倍,在高并发,快响应要求下的互联网系统中,对性 能的影响跟明显。

MyBatis对存储过程提供很好的支持

​ 开发工作量大不意味着学习成本大。对于新手,学习Hibernate时间成本比Mybatis大很多。

6.框架的使用

​ 1.简化了我们的代码

​ 2.框架底层复杂,难,各种设计模式和原理…

​ 3.框架的底层难,但不耽误我们使用框架

​ 4.导入jar包 书写配置文件 加入注解完毕

Mybatis项目搭建

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZAk8dmPN-1602321047628)(D:\Write\note\img\mybatis项目结构.png)]

1.导入jar包

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8883PaKk-1602321047629)(D:\Write\note\img\mybatis导包.png)]

2.准备MyBatis配置文件

​ jdbc.properties文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username=root
password=root

​ mybatis.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!--xml 文档约束 约束xml文档中可以有哪些标签那些属性 以及标签的包含关系和顺序两种方式约束:dtd 约束schema约束
-->
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties resource="jdbc.properties"></properties><settings><!--设置日志处理方式--><setting name="logImpl" value="LOG4J"/></settings><!--类型别名--><typeAliases><!--给一个类设置别名<typeAlias  alias="emp" type="com.test.pojo.Emp" ></typeAlias>--><!--通过包扫描给所有实体类起别名给指定包下的所有类名起别名,默认每个类的别名是首字母小写的类名列如: Dept -> dept--><package name="com.test.pojo"/></typeAliases><!-- 配置数据库连接信息 --><environments default="mysql"><environment id="mysql"><!--事务配置--><transactionManager type="JDBC"/><!--一个数据源--><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><!--jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai--><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment><!--数据源2--><!--<environment id="oracle"><transactionManager type="JDBC"/>&lt;!&ndash;一个数据源&ndash;&gt;<dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/>&lt;!&ndash;jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&ndash;&gt;<property name="url" value="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment>--></environments><!--加载映射文件--><mappers><mapper resource="com/test/mapper/DeptMapper.xml"/><mapper resource="com/test/mapper/EmpMappeer.xml"/></mappers>
</configuration>
3.创建实体类

public class Dept {private int deptno;private String dname;private String loc;public Dept(int deptno, String dname, String loc) {super();this.deptno = deptno;this.dname = dname;this.loc = loc;}public Dept() {super();}@Overridepublic String toString() {return "Dept{" +"deptno=" + deptno +", dname='" + dname + '\'' +", loc='" + loc + '\'' +'}';}
}
public class Emp implements Serializable {private int empno;private String ename;private String job;private int mgr;private Date hiredate;private double sal;private double comm;private int deptno;public Emp(int empno, String ename, String job, int mgr, Date hiredate, double sal, double comm, int deptno) {super();this.empno = empno;this.ename = ename;this.job = job;this.mgr = mgr;this.hiredate = hiredate;this.sal = sal;this.comm = comm;this.deptno = deptno;}public Emp() {super();}@Overridepublic String toString() {return "Emp [empno=" + empno + ", ename=" + ename + ", job=" + job + ", mgr=" + mgr + ", hiredate=" + hiredate+ ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + "]";}
}    
4.准备Mapper映射文件
    select标签         用于sql查询语句id        		  sql语句唯一表示parameterType  	   参数的数据类型resultType    	   返回值类型  查询的结果要封装成那个类的对象

​ EmpMappeer.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不能重名(xml文件中不能有重名)-->
<mapper namespace="EmpMapper"><!--select标签    用于sql查询语句id        sql语句唯一表示parameterType   参数的数据类型resultType    返回值类型  查询的结果要封装成那个类的对象--><!--<select id="selectByDeptno" resultType="com.test.pojo.Emp">select * from emp where empno= 7566</select>--><select id="selectByDeptno" resultType="emp">select * from emp where empno= 7566</select>
</mapper>

​ DeptMapper.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="DeptMapper"><!--  <select id="selectByEmpno"  resultType="com.test.pojo.Dept">select * from dept where deptno= 10</select>--><select id="selectByEmpno" resultType="dept">select * from dept where deptno= 10</select>
</mapper>
5.开发java代码
public class Test1 {public static void main(String[] args) throws IOException {//1.获取sqlSessionSqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();InputStream is = Resources.getResourceAsStream("mybatis.xml");//SqlSessionFactory sql语句会话对象工厂,专门用于生产SqlSession对象//build方法中需要传入一个输入流作为参数  输入流要指向我们的mybatis核心配置文件SqlSessionFactory factory = ssfb.build(is);//sql 语句会话对象 专门用于执行sql语句和返回结果SqlSession sqlSession = factory.openSession();//2.用sqlSession执行sql语句,完成关系映射处理Emp emp = sqlSession.selectOne("selectByDeptno");Dept dept = sqlSession.selectOne("selectByEmpno");System.out.println(emp);System.out.println(dept);//3.关闭sqlsession 释放资源sqlSession.close();}
}

MyBatis XML 文件配置信息

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

  • configuration(配置)

    • properties(属性)

    • settings(设置)

    • typeAliases(类型别名)

    • typeHandlers(类型处理器)

    • objectFactory(对象工厂)

    • plugins(插件)

    • environments(环境配置)

      • environment(环境变量)
        • transactionManager(事务管理器)
        • dataSource(数据源)
    • databaseIdProvider(数据库厂商标识)

    • mappers(映射器)

属性(properties)

<properties resource="jdbc.properties"></properties>

设置(settings)

设置参数描述有效值默认值
cacheEnabled这个配置使全局的映射器启用或禁用 缓存。true | falsetrue
lazyLoadingEnabled全局启用或禁用延迟加载。当禁用时, 所有关联对象都会即时加载。true | falsetrue
aggressiveLazyLoading当启用时, 有延迟加载属性的对象在被 调用时将会完全加载任意属性。否则, 每种属性将会按需要加载。true | falsetrue
multipleResultSetsEnabled允许或不允许多种结果集从一个单独 的语句中返回(需要适合的驱动)true | falsetrue
useColumnLabel使用列标签代替列名。 不同的驱动在这 方便表现不同。 参考驱动文档或充分测 试两种方法来决定所使用的驱动。true | falsetrue
useGeneratedKeys允许 JDBC 支持生成的键。 需要适合的 驱动。 如果设置为 true 则这个设置强制 生成的键被使用, 尽管一些驱动拒绝兼 容但仍然有效(比如 Derby)true | falseFalse
autoMappingBehavior指定 MyBatis 如何自动映射列到字段/ 属性。PARTIAL 只会自动映射简单, 没有嵌套的结果。FULL 会自动映射任 意复杂的结果(嵌套的或其他情况) 。NONE, PARTIAL, FULLPARTIAL
defaultExecutorType配置默认的执行器。SIMPLE 执行器没 有什么特别之处。REUSE 执行器重用 预处理语句。BATCH 执行器重用语句 和批量更新SIMPLE REUSE BATCHSIMPLE
defaultStatementTimeout设置超时时间, 它决定驱动等待一个数 据库响应的时间。Any positive integerNot Set (null)
safeRowBoundsEnabledAllows using RowBounds on nested statements.true | falseFalse
mapUnderscoreToCamelCaseEnables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn.true | falseFalse
localCacheScopeMyBatis uses local cache to prevent circular references and speed up repeated nested queries. By default (SESSION) all queries executed during a session are cached. If localCacheScope=STATEMENT local session will be used just for statement execution, no data will be shared between two different calls to the same SqlSession.SESSION | STATEMENTSESSION
jdbcTypeForNullSpecifies the JDBC type for null values when no specific JDBC type was provided for the parameter. Some drivers require specifying the column JDBC type but others work with generic values like NULL, VARCHAR or OTHER.JdbcType enumeration. Most common are: NULL, VARCHAR and OTHEROTHER
lazyLoadTriggerMethodsSpecifies which Object’s methods trigger a lazy loadA method name list separated by commasequals,clone,hashCode,toString
defaultScriptingLanguageSpecifies the language used by default for dynamic SQL generation.A type alias or fully qualified class name.org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver
callSettersOnNulls当结果集中含有Null值时是否执行映射对象的setter或者Map对象的put方法。此设置对于原始类型如int,boolean等无效。true | falsefalse
logPrefixSpecifies the prefix string that MyBatis will add to the logger names.Any StringNot set
logImplSpecifies which logging implementation MyBatis should use. If this setting is not present logging implementation will be autodiscovered.SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGINGNot set
proxyFactorySpecifies the proxy tool that MyBatis will use for creating lazy loading capable objects.CGLIB | JAVASSISTCGLIB

类型别名(typeAliases)

​ 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

<typeAliases><typeAlias alias="Author" type="domain.blog.Author"/><typeAlias alias="Blog" type="domain.blog.Blog"/><typeAlias alias="Comment" type="domain.blog.Comment"/><typeAlias alias="Post" type="domain.blog.Post"/><typeAlias alias="Section" type="domain.blog.Section"/><typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

类型处理器(typeHandlers)

​ 无论是 MyBatis 在预处理语句中设置一个参数, 还是从结果集中取出一个值时, 类型处理器被用来将获取的值以合适的方式转换成 Java 类型。下面这个表格描述了默认的类型处理器。

处理枚举类型

对象工厂(objectFactory)

​ 每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作

插件(plugins)

环境配置(environments)

事务管理器(transactionManager)

在 MyBatis 中有两种类型的事务管理器

  • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为
数据源(dataSource)

​ dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

数据库厂商标识(databaseIdProvider)

​ MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载带有匹配当前数据库 databaseId 属性和所有不带 databaseId 属性的语句

映射器(mappers)

映射文件加载方式

1.mapper映射文件的文件路径导入 使用的mapper标签的resource属性

<!-- 使用相对于类路径的资源引用 -->
<mappers><mapper resource="org/mybatis/builder/AuthorMapper.xml"/><mapper resource="org/mybatis/builder/BlogMapper.xml"/><mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

2.网络资源路径 使用mapper标签的url属性

<!-- 使用完全限定资源定位符(URL) -->
<mappers><mapper url="file:///var/mappers/AuthorMapper.xml"/><mapper url="file:///var/mappers/BlogMapper.xml"/><mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

3.接口的全限定名导入 使用的是mapper标签的class属性 (基于接口的代理模式开发)

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers><mapper class="org.mybatis.builder.AuthorMapper"/><mapper class="org.mybatis.builder.BlogMapper"/><mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

4.包扫描形式加载所有的mapper映射文件 使用的是 package标签

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers><package name="org.mybatis.builder"/>
</mappers>

MyBatis XML映射文件

  • insert – 映射插入语句

  • update – 映射更新语句

  • delete – 映射删除语句

  • select – 映射查询语句

    select

<select id="selectPerson" parameterType="int" resultType="hashmap">SELECT * FROM PERSON WHERE ID = #{id}
</select>
<?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不能重名(xml文件中不能有重名)-->
<mapper namespace="EmpMapper"><!--select标签    用于sql查询语句id        sql语句唯一表示parameterType   参数的数据类型resultType    返回值类型  查询的结果要封装成那个类的对象--><!--查询单个对象 根据员工编号查询员工信息--><select id="findOne" parameterType="int" resultType="emp">select * from emp where empno= #{id}</select>
</mapper>
#{ } 和 ${ }的区别

${} 代表MyBatis 底层使用Statement对象处理参数
参数采用字符串拼接的方式放入sql语句中
#{} 代表MyBatis 底层使用PreparedStatement对象处理参数
参数采用?作为占位符,对sql语句进行预处理后执行

update

<!-- 增删改语句都是返回int所以insert delete update 没有 resultType属性-->
<update id="updateEmp" parameterType="map">update emp set ename=#{ename} where empno=#{empno}</update>

delete

 <!--删除数据 根据员工编号删除员工信息--><delete id="deleteEmp" parameterType="int">delete from emp  where empno=#{empno}</delete>

insert

 <!--向emp表中增加一条数据--><insert id="addEmp" parameterType="emp">insert  into emp (ename,job,sal)values(#{ename},#{job},#{sal})</insert>

封装SqlSessionFactory 简化SqlSession对象的创建

public class SqlSessionUtil {private static SqlSessionFactory factory = null;static {//1.获取sqlSessionSqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();InputStream is = null;try {is = Resources.getResourceAsStream("mybatis.xml");} catch (IOException e) {e.printStackTrace();}//SqlSessionFactory sql语句会话对象工厂,专门用于生产SqlSession对象//build方法中需要传入一个输入流作为参数  输入流要指向我们的mybatis核心配置文件factory = ssfb.build(is);}public static SqlSession getSqlSession() {//sql 语句会话对象 专门用于执行sql语句和返回结果SqlSession sqlSession = factory.openSession();return sqlSession;}public static SqlSession getSqlSession(boolean flag) {/** factory.openSession(flag);* true  事务自动提交* false 事务手动提交* */SqlSession sqlSession = factory.openSession(flag);return sqlSession;}
}

MyBatis查询的三种方式(SqlSession API)

  • SqlSession.selectOne( ) 返回一个对象

  • Sqlsession.selectList( ) 返回集合

  • Sqlsession.SelectMap( ) 返回Map

    mapper映射

<?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不能重名(xml文件中不能有重名)-->
<mapper namespace="EmpMapper"><!--select标签    用于sql查询语句id        sql语句唯一表示parameterType   参数的数据类型resultType    返回值类型  查询的结果要封装成那个类的对象--><!--查询单个对象 根据员工编号查询员工信息--><select id="findOne" parameterType="int" resultType="emp">select * from emp where empno= #{id}</select><!--查询多个对象的List集合--><select id="findAll" parameterType="int" resultType="emp">select * from emp</select><!--查询多个对象的map集合--><select id="findEmpMap"  resultType="map">select * from emp</select>
</mapper>

​ Java代码

public class TestSelect {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession();//查询单个对象Emp findOne = sqlSession.selectOne("EmpMapper.findOne", 7566);//查询多个象的List集合List<Emp> findAll = sqlSession.selectList("findAll");System.out.println(findOne);findAll.forEach(System.out::println);// 查询多个对象的map集合Map<Integer, Emp> empMap = sqlSession.selectMap("findEmpMap", "EMPNO");Set<Map.Entry<Integer, Emp>> eKey = empMap.entrySet();//eKey.forEach((s)->System.out.println(s +" "+ s.getValue()));eKey.forEach(System.out::println);sqlSession.close();}

mybatis参数传递的三种方式

1.单个基本数据作为参数

2.多个数据类型的map集合作为参数

3.引用类型作为参数

​ mapper映射

<?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="EmpMapper2"><!--单个基本数据类型作为参数查询单个对象 根据员工编号查询员工信息大括号里面可以随便写--><select id="findByEmpno" parameterType="int" resultType="emp">select * from emp where empno= #{empno}</select><!--多个基础数据类型的Map集合作为参数查询指定部门的 高于指定薪资的员工信息大括号中应填写Map集合的key--><select id="findByEmpAndSal" parameterType="map"  resultType="emp">select * from emp where deptno=#{a} and sal >#{b}</select><!--单个引用类型作为参数大括号中应填写引用类型的属性名--><select id="findByEmpAndSal2" parameterType="emp"  resultType="emp">select * from emp where deptno=#{deptno} and sal >#{sal}</select>
</mapper>

​ Java代码

public class TestSelect2 {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession();//查询单个对象Emp findOne = sqlSession.selectOne("findByEmpno", 7566);System.out.println(findOne);// 查询多个对象的List集合Map<String,Object> param1=new HashMap<>();param1.put("a",10);param1.put("b",1500);List<Emp> empList = sqlSession.selectList("findByEmpAndSal", param1);empList.forEach(System.out::println);// 查询多个对象的map集合 sql语句的id  map集合中键的名称Emp param2 =new Emp();param2.setDeptno(10);param2.setSal(1500);List<Emp> empList2 = sqlSession.selectList("findByEmpAndSal2", param2);empList2.forEach(System.out::println);sqlSession.close();}
}

MyBatis文件配置细节

1.log4j的使用

​ 将log4j.properties文件放入src下

#定义全局日志级别调试阶段推荐debug
log4j.rootLogger=debug,stdout 
#包级别日志 调试阶段推荐debug
log4j.logger.com.bjsxt.mapper=debuglog4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayoutlog4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/bjsxt.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n

​ 在XML映射文件中配置文件

<settings><!--设置日志处理方式--><setting name="logImpl" value="LOG4J"/>
</settings>

2.实体类别名处理

​ 在MyBatis核心配置文件中使用别名处理

 <!--类型别名--><typeAliases><!--给一个类设置别名<typeAlias  alias="emp" type="com.Emp" ></typeAlias>--><!--通过包扫描给所有实体类起别名给指定包下的所有类名起别名,默认每个类的别名是首字母小写的类名列如: Dept -> dept--><package name="com.test.pojo"/></typeAliases>

3.外部属性文件配置

<!--读取properties文件--><properties resource="jdbc.properties"></properties>

MyBatis 事务管理

  • SqlSessionFactory.openSession(false|true) 开启 事务自动提交

  • SqlSession.rollback() 事务回滚

  • SqlSession.commit() 事务提交

    SqlSession默认事务是自动打开的,增删改需要调用commit方法才能提交
    可以设置mybatis事务自动提交
    factory.openSession(true);设置事务自动提交

    public class TestAccount {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession();try {Account account = new Account(1, (double) 100);Account account2 = new Account(2, (double) -100);sqlSession.update("updateAccount",account);//int a =1/0;sqlSession.update("updateAccount",account2);} catch (Exception e) {//回滚事务sqlSession.rollback();e.printStackTrace();}finally {//提交事务sqlSession.commit();sqlSession.close();}}
    }
    

mybatis完成DML操作

<?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="EmpMapper3"><!--增删改语句都是返回int所以insert delete update 没有 resultType属性--><!--向emp表中增加一条数据--><insert id="addEmp" parameterType="emp">insert  into emp (ename,job,sal)values(#{ename},#{job},#{sal})</insert><!--修改一条数据  根据员工编号修改员工姓名--><update id="updateEmp" parameterType="map">update emp set ename=#{ename} where empno=#{empno}</update><!--删除数据 根据员工编号删除员工信息--><delete id="deleteEmp" parameterType="int">delete from emp  where empno=#{empno}</delete>
</mapper>

测试代码

public class TestIUD {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);/*//增加数据Emp emp = new Emp();emp.setSal(2000);emp.setJob("SALESMAN");emp.setEname("SAL");int rows = sqlSession.insert("addEmp",emp);//sqlSession.commit();System.out.println(rows);*//*//修改数据Map<String, Object> params = new HashMap<>();params.put("ename", "小白");params.put("empno", 7939);int rows = sqlSession.update("updateEmp", params);*///删除数据sqlSession.delete("deleteEmp",7939);sqlSession.close();}
}

使用Mapper代理

在MyBatis中提供了另外一种成为**Mapper代理(或称为接口绑定)**的操作方式

  • 1.接口的名字和映射文件的名字必须相同
  • 2.namespace中的内容必须是接口的全限定名
  • 3.sql语句的id必须是对应方法的方法名

传统DAO模式开发

都是sqlSession调用自身方法发送SQL命令并得到结果。

 缺点:

​ 1. 不管是selectList()、selectOne()、selectMap(),都是通过SQLSession对象的API完成增删改查,都只能提供一 个查询参数。如果要多个参数,需要封装到JavaBean或者Map中,并不一定永远是一个好办法。

​ 2.返回值类型较固定。

​ 3.只提供了映射文件,没有提供数据库操作的接口,不利于后期的维护扩展。

Mapper代理模式开发:

​ 优点:

​ 1.有接口 模块之间有规范了

​ 2.参数的处理多样了,接口中的方法参数列表由我们自己决定

​ 3.通过代理模式由mybatis提供接口的实现类对象 我们不用写实现类了

代理模式作用

在不修改代理对象代码得情况下实现功能的增强和功能增加,让功能的增加和撤销不影响原有的代码,可以极大的降低代码的耦合度 。

AOP 、连接池 、servlet 编码 过滤器 mybatis内部都是用代理模式

代理模式下的参数传递

1.单个基本数据类型传递
 /*** 根据员工编号查询单个员工信息* @param empno 员工的编号* @return 员工对象 如果未找到返回null*/Emp getByEmpno(int empno);
    <!--1.单个基本数据类型作为方法参数Emp getByEmpno(int empno);单个基本数据类型作为方法参数 #{}中的名字可以随便写--><select id="getByEmpno" resultType="emp" parameterType="int">select * from emp where empno=#{empno}</select>
2.多个基本数据传递
    /*** 根据部门号和工资下限查询员工信息** @param deptno 部门号* @param sal    工资的下限* @return Employee对象List集合*/List<Emp> getByDeptAndSal(@Param("a") int deptno, @Param("b") double sal);
    <!--2.多个基本数据类型作为方法参数List<Emp> getByDeptAndSal(@Param("a")  int deptno, @Param("b") double sal);1 #{} 中可以写arg0  arg1  arg*  *参数的索引 从0开始 {10,1500}2 #{} 可以写 param1 param2 param* *参数的位置编号 从1开始3 #{}  接口上可以使用@Param注解为参数起别名 #{} 中可以放参数的别名--><select id="getByDeptAndSal" resultType="emp"><!-- select * from emp where deptno=#{arg0} and sal>#{arg1}--><!--  select * from emp where deptno=#{param1} and sal>#{param2}-->select * from emp where deptno=#{a} and sal>#{b}</select>
3.单个引用数据类型传递
/*** 根据部门号和工资下限查询员工信息** @param emp 工资和部门号作为emp对象的属性传递* @return Employee对象List集合*/List<Emp> getByDeptAndSal2(Emp emp);
    <!--3.单个引用类型作为方法参数List<Emp> getByDeptAndSal2(Emp emp);#{deptno} 会找引用类型中属性名为deptno#{} 中要写对象的属性名--><select id="getByDeptAndSal2" resultType="emp">select * from emp where deptno=#{deptno} and sal>#{sal}</select>
4.多个引用数据类型传递
 /*** 根据部门号和工资下限查询员工信息** @param deptnoEmp 用于存储部门号的Emp对象* @param salEmp    用于存储工资的emp对对象* @return Employee对象List集合*/List<Emp> getByDeptAndSal3(@Param("a") Emp deptnoEmp, @Param("b") Emp salEmp);
    <!--4.多个引用类型作为方法参数List<Emp> getByDeptAndSal3( @Param("a") Emp deptEmp, @Param("b") Emp salEmp);1#{} 中写法为  arg*.对象的属性名2#{} 中写法为  param*.对象的属性名3#{} 当参数列表中使用@Param添加别名 #{}中可以使用别名.对象的属性名--><select id="getByDeptAndSal3" resultType="emp"><!--select * from emp where deptno=#{arg0.deptno} and sal>#{arg1.sal}--><!--select * from emp where deptno=#{param.deptno} and sal>#{param.sal}-->select * from emp where deptno=#{a.deptno} and sal>#{b.sal}</select>
测试代码
public class Test1 {public static void main(String[] args) {SqlSession sqlSession= SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);// 1单个基本数据类型作为方法参数Emp byEmpno = mapper.getByEmpno(7902);System.out.println(byEmpno);// 2多个基本数据类型作为方法参数List<Emp> byDeptAndSal = mapper.getByDeptAndSal(10, 1500);byDeptAndSal.forEach(System.out::println);// 3单个引用类型作为方法参数Emp emp =new Emp();emp.setDeptno(10);emp.setSal(1500);List<Emp> byDeptAndSal2 = mapper.getByDeptAndSal2(emp);byDeptAndSal2.forEach(System.out::println);// 4多个引用类型作为方法参数Emp emp1 =new Emp();Emp emp2 =new Emp();emp1.setDeptno(10);emp2.setSal(1500);List<Emp> byDeptAndSal3 = mapper.getByDeptAndSal3(emp1,emp2);byDeptAndSal3.forEach(System.out::println);sqlSession.close();}
}

模糊查询

在进行模糊查询时,在映射文件中可以使用**concat()**函数来连接参数和通配符。另外注意对于特殊字符,比如<,不能直接书写,应该使用字符实体替换

    /*** 根据名字做模糊查询** @param name 模糊查询的文字* @return Emp对象List集合*/List<Emp> getByName(String name);
    <!--模糊查询实现方式List<Emp> getByName(String name);--><select id="getByName" parameterType="string" resultType="emp">select * from emp  where ename like concat( '%',#{ename},'%')</select>
public class Test2 {public static void main(String[] args) {SqlSession sqlSession= SqlSessionUtil.getSqlSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);List<Emp> a = mapper.getByName("a");a.forEach(System.out::println);}
}

自增主键回填

MySQL支持主键自增。有时候完成添加后需要立刻获取刚刚自增的主键,由下一个操作来使用

方式一:

​ useGeneratedKeys:表示要使用自增的主键

​ keyProperty:表示把自增的主键赋给JavaBean的哪个成员变量

方式二:

​ order:取值AFTER|BEFORE,表示在新增之后|之前执行中的SQL命令

​ keyProperty:执行select @@identity后结果填充到哪个属性中

​ resultType:结果类型。

接口

public interface DeptMapper {/*** 功能描述:插入一条数据*/int addDept(Dept dept);int addDept2(Dept dept);/*** 删一条数据* */int deleteDept(int  dept);/*** 修改一条数据* */int updateDept(Dept  dept);
}

mapper映射

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--1.接口的名字和映射文件的名字必须相同2.namespace 中内容中必须是接口的全名3.select标签的id属性必须是对应的方法名
-->
<mapper namespace="com.test.mapper.DeptMapper"><insert id="addDept" parameterType="dept" useGeneratedKeys="true"keyProperty="deptno" >insert into dept values(null,#{dname},#{loc})</insert><insert id="addDept2" parameterType="dept" ><selectKey order="AFTER" keyProperty="deptno" resultType="int">select@@identity </selectKey>insert into dept values(null,#{dname},#{loc})</insert><!-- int deleteDept(int  dept);--><delete id="deleteDept" parameterType="int">delete from dept where deptno=#{deptno}</delete><!-- int updateDept(Dept  dept);--><update id="updateDept" parameterType="dept">update dept set dname = #{dname} where deptno=#{deptno}</update></mapper>

测试代码

public class Test3 {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);/*插入输入据*/Dept dept = new Dept();dept.setDname("后勤部");dept.setLoc("上海");int i = mapper.addDept(dept);//自增主键回填System.out.println(i+"  "+dept.getDeptno());/*插入输入据*/Dept dept2 = new Dept();dept2.setDname("销售部");dept2.setLoc("上海");i =  mapper.addDept2(dept2);System.out.println(i+"  "+dept2.getDeptno());/*修改数据*/dept.setDname("卫生部");i= mapper.updateDept(dept);System.out.println(i);//删除数据i =mapper.deleteDept(dept.getDeptno());System.out.println(i);}
}

动态SQL语句

用于多条件查询 动态生成SQL语句

MyBatis在简化操作方法提出了动态SQL功能,将使用Java代码拼接SQL语句,改变为在XML映射文件中截止标签拼接SQL语句。相比而言,大大减少了代码量,更灵活、高度可配置、利于后期维护。

MyBatis中动态SQL是编写在mapper.xml中的,其语法和JSTL类似,但是却是基于强大的OGNL表达式实现的。

MyBatis也可以在注解中配置SQL,但是由于注解功能受限,尤其是对于复杂的SQL语句,可读性很差,所以较少使用

if标签

<select id="findEmpByCondition" resultType="emp">select * from emp  WHERE 1=1<if test="empno != null">and empno= #{empno}</if><if test="ename != null and ename != ''">and ename= #{ename}</if><if test="job != null and job != ''">and job= #{job}</if><if test="mgr != null ">and mgr= #{mgr}</if><if test="hiredate != null ">and hiredate= #{hiredate}</if><if test="sal != null">and sal= #{sal}</if><if test="comm != null ">and comm =#{comm}</if><if test="deptno != null ">and deptno= #{deptno}</if>
</select>

where标签

    <select id="findByConditionEmp" resultType="emp"><include refid="baseEmpQuery"/><where><if test="empno != null and empno!=0 ">and empno= #{empno}</if><if test="ename != null and ename != ''">and ename= #{ename}</if><if test="job != null and job != ''">and job= #{job}</if><if test="mgr != null and mgr!=0 ">and mgr= #{mgr}</if><if test="hiredate != null ">and hiredate= #{hiredate}</if><if test="sal != null and sal!=0 ">and sal= #{sal}</if><if test="comm != null and comm!=0 ">and comm =#{comm}</if><if test="deptno != null and comm !=0 ">and deptno= #{deptno}</if></where></select>

choose标签

<select id="findByConditionEmp2" resultType="emp"><include refid="baseEmpQuery"/><where><choose><when test="empno != null and empno!=0 ">and empno= #{empno}</when><when test="ename != null and ename != ''">and ename= #{ename}</when><when test="job != null and job != ''">and job= #{job}</when><when test="mgr != null and mgr!=0 ">and mgr= #{mgr}</when><when test="hiredate != null ">and hiredate= #{hiredate}</when><when test="sal != null and sal!=0 ">and sal= #{sal}</when><when test="comm != null and comm!=0 ">and comm =#{comm}</when><when test="deptno != null and comm !=0 ">and deptno= #{deptno}</when></choose></where></select>

set标签

<update id="updateEmp" parameterType="emp">update emp<set><if test="ename != null and ename != ''">ename= #{ename},</if><if test="job != null and job != ''">job= #{job},</if><if test="mgr != null and mgr!=0 ">mgr= #{mgr},</if><if test="hiredate != null ">hiredate= #{hiredate},</if><if test="sal != null and sal!=0 ">sal= #{sal},</if><if test="comm != null and comm!=0 ">comm =#{comm},</if><if test="deptno != null and comm !=0 ">deptno= #{deptno},</if></set>where empno= #{empno}
</update>

trim标签

<update id="updateEmp2" parameterType="emp">update emp<trim prefix="set" suffixOverrides=","><if test="ename != null and ename != ''">ename= #{ename},</if><if test="job != null and job != ''">job= #{job},</if><if test="mgr != null and mgr!=0 ">mgr= #{mgr},</if><if test="hiredate != null ">hiredate= #{hiredate},</if><if test="sal != null and sal!=0 ">sal= #{sal},</if><if test="comm != null and comm!=0 ">comm =#{comm},</if><if test="deptno != null and comm !=0 ">deptno= #{deptno},</if></trim>where empno= #{empno}
</update>

foreach标签

<select id="findByDeptno" resultType="emp"><include refid="baseEmpQuery"/> where deptno in<foreach collection="list" item="deptno" open="("  separator=","  close=")" >#{deptno}</foreach>
</select>

bind标签

<select id="findByEname" parameterType="string" resultType="emp"><bind name="lisePattern" value="'%'+ename+'%'"/>select * from emp where ename like  #{lisePattern}
</select>

sql标签

<sql id="empColumns">empno,ename,job,mgr,hiredate,sal,comm,deptno
</sql>
<sql id="baseEmpQuery">select<include refid="empColumns"/>from emp
</sql>

Mybatis 缓存

什么是缓存

​ 缓存就是数据交换得缓冲区(称作:Cache),当某一硬件要读取数据时,会首先从缓存中汇总查询数据,有则直接执行,不存在时从内存中获取。由于缓存的数据比内存快的多,所以缓存的作用就是帮助硬件更快的运行

一级缓存

​ 一级存储是SqlSession上的缓存,默认开启,不要求实体类对象实现Serializable接口,占用内存

​ commit方法会刷新一级缓存(增删改动作,如果不修改会造成数据不同步)

 public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);Emp emp = mapper.findByEmpNo(7782);System.out.println(emp);//commit方法会刷新一级缓存 跟事务自动提交没有关系sqlSession.commit();Emp emp2 = mapper.findByEmpNo(7782);System.out.println(emp2);sqlSession.close();}

二级缓存

二级缓存时以namespace为标记的缓存,可以是由一个SqlSessionFactory创建的SqlSession之间共享缓存数据

默认不开启

缺点:容易造成数据不同步,产生较高的占用空间

二级缓存实现条件

​ 1.全局开关:在mybatis-config.xml文件中的**settings**标签配置开启二级缓存

​ 2.分开关:在要开启二级缓存的mapper文件中开启缓存 **cache**标签

​ 3. 缓存中存储的JavaBean对象必须实现序列化接口

二级缓存注意事项

​ 1.MyBatis的二级缓存的缓存介质有多种多样,而并不一定是在内存中,所以需要对JavaBean对象实现序 列化接口

​ 2. 二级缓存时以namespace为单位的,不同namespace下操作互不影响

​ 3.cache标签 有一些可选属性

           <cache  type="" readOnly="" eviction="" flushInterval="" size="" blocking=""/>

​ 4.如果在加入Cache元素的前提下让个别select 元素不使用缓存,可以使用useCache属性,设置为false

flushCache控制当前sql语句刷新后是否刷新缓存 如果刷新将清除原来的缓存

 <!--useCache="true" 使用缓存 false不使用缓存-->
<select id="findByEmpNo" resultType="emp" useCache="true" flushCache="true">select * from emp where empno =#{empno}</select>
</mapper>

​ 5.加入Cache元素后,会对相应命名空间所有的select元素查询结果进行缓存,而其中的insert、update、 delete操作是会清空整个namespace的缓存

在没有开启二级缓存的情况下代码演示
    public static void main(String[] args) {/*使用第一个SqlSession 查询数据*/SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);Emp emp = mapper.findByEmpNo(7782);System.out.println(emp);sqlSession.close();/*使用第二个SqlSession 查询数据*/SqlSession sqlSession2 = SqlSessionUtil.getSqlSession(true);EmpMapper mapper2 = sqlSession2.getMapper(EmpMapper.class);Emp emp2 = mapper2.findByEmpNo(7782);System.out.println(emp2);sqlSession2.close();}
开启二级缓存的情况下代码演示

​ 1.需要在xml映射配置文件中**settings**标签配置开启二级缓存

cacheEnabled的默认值就是true,所以这步的设置可以省略

<settings><!--开启全局缓存-->      <setting name="cacheEnabled" value="true"/></settings>

​ 2.开启namesapce下缓存设置 加入**cache** 标签

<?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="com.test.mapper.EmpMapper"><!--开启缓存--><cache/>   <!--useCache="true" 使用缓存 false不使用缓存flushCache控制当前sql语句刷新后是否刷新缓存	--><select id="findByEmpNo" resultType="emp" useCache="true" flushCache="true">select * from emp where empno =#{empno}</select>
</mapper>

​ 3.测试代码

    public static void main(String[] args) {/*使用第一个SqlSession 查询数据*/SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);Emp emp = mapper.findByEmpNo(7782);System.out.println(emp);//调用commit()才会存入缓存sqlSession.commit();/*不关闭不会存入缓存 关闭时会提交数据* 不提交下一个SqlSession才能从缓存中取到数据* */// sqlSession.close();/*使用第二个SqlSession 查询数据*/SqlSession sqlSession2 = SqlSessionUtil.getSqlSession(true);EmpMapper mapper2 = sqlSession2.getMapper(EmpMapper.class);Emp emp2 = mapper2.findByEmpNo(7782);System.out.println(emp2);sqlSession2.close();}

二级缓存容易造成问题:数据脏读

​ 第一次启动缓存读取数据,第二次停止10秒,期间修改数据库表中数据,

​ 读取缓存中数据与数据库不一致 容易造成数据不同步,产生较高的占用空间

代码演示
public static void main(String[] args) {/*使用第一个SqlSession 查询数据*/SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);Emp emp = mapper.findByEmpNo(7782);System.out.println(emp);sqlSession.close();try {//休眠10秒Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}/*使用第二个SqlSession 查询数据*/SqlSession sqlSession2 = SqlSessionUtil.getSqlSession(true);EmpMapper mapper2 = sqlSession2.getMapper(EmpMapper.class);Emp emp2 = mapper2.findByEmpNo(7782);System.out.println(emp2);sqlSession2.close();}

MyBatis手动处理映射关系

​ 简单理解就是手动封装成实体类

​ 数据库字段名 和 实体类属性名不一致时需要手动处理映射关系

public class Emp  implements Serializable {private Integer empno;private String name;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;
<mapper namespace="com.bjsxt.mapper.EmpMapper"><!--type生成对象property 对应实体类属性名字column   对应数据库表中字段的名字id       代表数据库表主键列手动处理数据库查询字段和封装实体类属性之间的映射关系1 主键一般使用id属性2 当属性名和查询出的数据表字段名相同 可以不写映射关系--><resultMap id="empMap" type="emp"><!--当属性名和查询出的数据表字段名相同 可以不写映射关系--><!--<id property="empno" column="empno"></id>--><result property="name" column="ename"></result><!--<result property="job" column="job"></result><result property="sal" column="sal"></result><result property="hiredate" column="hiredate"></result><result property="mgr" column="mgr"></result><result property="comm" column="comm"></result><result property="deptno" column="deptno"></result>--></resultMap><select id="findByEmpno" resultMap="empMap" >select * from emp where empno =#{empno}

MyBatis多表查询

resultMap中的常见属性
属性描述
property需要映射到JavaBean 的属性名称。
javaTypeproperty的类型,一个完整的类名,或者是一个类型别名。如果你匹配的是一个JavaBean,那MyBatis 通常会自行检测到。
column数据表的列名或者列别名。
jdbcTypecolumn在数据库表中的类型。这个属性只在insert,update 或delete 的时候针对允许空的列有用。JDBC 需要这项,但MyBatis 不需要。
typeHandler使用这个属性可以覆写类型处理器,实现javaType、jdbcType之间的相互转换。一般可以省略,会探测到使用的什么类型的typeHandler进行处理
fetchType自动延迟加载
selectassociation、collection的属性,使用哪个查询查询属性的值,要求指定namespace+id的全名称
ofTypecollection的属性,指明集合中元素的类型(即泛型类型)

关联查询

MyBatis 一对一关联查询

    /*** 功能描述:根据员工编号查询员工信息及所在部门信息* @param: empno 员工编号* @return: 带有部门作为属性的员工对象*/Emp findByJoinDept(int empno);/*** 功能描述:根据员工编号查询员工信息及薪水等级* @param: empno 员工编号* @return: 员工信息及薪水等级*/Emp findByEmpNoGrade(int empno);

实体类

    private Integer empno;private String ename;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;private Dept dept;private Salgrade salgrade;public Salgrade getSalgrade() {return salgrade;}public void setSalgrade(Salgrade salgrade) {this.salgrade = salgrade;}public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept = dept;}

mapper映射文件

<!--使用resultMap定义一对一映射关系--><resultMap id="empJoinDept" type="emp"><!--处理emp原有8个属性 不能省略--><id property="empno" column="empno"></id><result property="ename" column="ename"></result><result property="job" column="job"></result><result property="sal" column="sal"></result><result property="hiredate" column="hiredate"></result><result property="mgr" column="mgr"></result><result property="comm" column="comm"></result><result property="deptno" column="deptno"></result><!--将deptno dname loc 映射景dept属性association 处理一对一映射关系property 给实体类属性赋值javaType 要映射的属性是哪个类--><association property="dept" javaType="dept" ><!--处理一对一属性映射--><id property="deptno" column="deptno"></id><result property="dname" column="dname"></result><result property="loc" column="loc"></result></association></resultMap><!--Emp findByJoinDept(int empno);--><select id="findByJoinDept" resultMap="empJoinDept">select * from emp eleft outer join dept don e.deptno=d.deptno where empno=#{empno}</select><resultMap id="empJoinSalgrade" type="emp"><!--处理emp原有8个属性 不能省略--><id property="empno" column="empno"></id><result property="ename" column="ename"></result><result property="job" column="job"></result><result property="sal" column="sal"></result><result property="hiredate" column="hiredate"></result><result property="mgr" column="mgr"></result><result property="comm" column="comm"></result><result property="deptno" column="deptno"></result><!--将deptno dname loc 映射景dept属性association 处理一对一映射关系property 给实体类属性赋值javaType 要映射的属性是哪个类--><association property="salgrade" javaType="salgrade" ><!--处理一对一属性映射--><id property="grade" column="grade"></id><result property="losal" column="losal"></result><result property="hisal" column="hisal"></result></association></resultMap>
<select id="findByEmpNoGrade" resultMap="empJoinSalgrade">select * from emp ejoin salgrade swhere e.empno=#{empno}GROUP BY sal BETWEEN s.losal and s.hisal
</select>

测试代码

public class Test2 {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);//根据员工编号查询员工信息及所在部门信息Emp emp = mapper.findByJoinDept(1);System.out.println(emp);System.out.println(emp.getDept());//根据员工编号查询员工信息及薪水等级Emp emp2 = mapper.findByEmpNoGrade(1);System.out.println(emp2);System.out.println(emp2.getSalgrade());}
}

MyBatis 一对多关联查询

   /*** 功能描述:根据部门编号 查询该部门所有有员工星信息* @param: deptno 要查询部门编号* @return: 该部门所有员工信息*/Dept getDeptJoinEmps(int deptno);

实体类

  private Integer deptno;private String dname;private String loc;private List<Emp> emps;public List<Emp> getEmps() {return emps;}public void setEmps(List<Emp> emps) {this.emps = emps;}

mapper映射文件

<!--使用resultMap处理一对多关系 -->
<resultMap id="deptJoinEmps" type="dept"><!--处理Dept原本的三个属性映射关系--><id property="deptno" column="deptno"></id><result property="dname" column="dname"></result><result property="loc" column="loc"></result><!--dept 关联多个emp对象的映射关系--><collection property="emps" ofType="emp"><!--处理一对多的每个属性映射关系--><id property="empno" column="empno"></id><result property="ename" column="ename"></result><result property="job" column="job"></result><result property="sal" column="sal"></result><result property="hiredate" column="hiredate"></result><result property="mgr" column="mgr"></result><result property="comm" column="comm"></result><result property="deptno" column="deptno"></result></collection>
</resultMap>
<!--根据部门编号 查询该部门所有有员工星信息-->
<select id="getDeptJoinEmps" resultMap="deptJoinEmps">select * from dept d left outer join emp eon e.deptno=d.deptnowhere d.deptno=#{deptno}
</select>
MyBatis多对多关联查询

接口

public interface ProjectsMapper {/*根据编号查询项目有哪些员工参与过*/Projects findProjectsJoinEmps(int pid);
}

实体类

public class Projects implements Serializable {private Integer pid;private String pname;private Integer money;private List<Projectrecords> projectrecords;public List<Projectrecords> getProjectrecords() {return projectrecords;}public void setProjectrecords(List<Projectrecords> projectrecords) {this.projectrecords = projectrecords;}
}
public class Projectrecords implements Serializable {private Integer empno;private Integer pid;private Emp emp;public Emp getEmp() {return emp;}public void setEmp(Emp emp) {this.emp = emp;}
}

mapper映射文件

<resultMap id="projectsJoinEmpsMap" type="projects"><id property="pid" column="pid"></id><result property="pname" column="pname"></result><result property="money" column="money"></result><collection property="projectrecords" ofType="projectrecords"><id property="empno" column="empno"></id><id property="pid" column="pid"></id><association property="emp" javaType="emp"><id property="empno" column="empno"></id><result property="ename" column="ename"></result><result property="job" column="job"></result><result property="sal" column="sal"></result><result property="hiredate" column="hiredate"></result><result property="mgr" column="mgr"></result><result property="comm" column="comm"></result><result property="deptno" column="deptno"></result></association></collection>
</resultMap><!--根据编号查询项目有哪些员工参与过-->
<select id="findProjectsJoinEmps" resultMap="projectsJoinEmpsMap">select * fromprojects  pc left outer join projectrecords  pon pc.pid=p.pidleft outer join emp eon e.empno =p.empnowhere pc.pid= #{pid}
</select>

测试代码

public class Test2 {public static void main(String[] args) {SqlSession sqlSession= SqlSessionUtil.getSqlSession(false);ProjectsMapper mapper = sqlSession.getMapper(ProjectsMapper.class);Projects pro = mapper.findProjectsJoinEmps(2);System.out.println(pro);//根据编号查询项目有哪些员工参与过List<Projectrecords> projectrecords = pro.getProjectrecords();for(Projectrecords s:projectrecords){System.out.println( s +s.getEmp().toString());;}}
}

级联查询

​ 级联查询,利用数据库表之间的外键关联进行自动的级联查询

​ 多条查询分开查询 级联查询将一个多表关联查询转换成多个单表查询,sql语句变得简单了, 单次单表查询比单次表查询效率更高,相应速度更快

​ 级联查询缺点:关联查询转换成级联查询,由原来的一次查询转换成多次查询,工作总量 是增多的。

级联查询和多表查询的比较及其选择
级联查询多表查询
SQL语句数量多条一条
性能性能低性能高
延迟加载立即加载、延迟加载只有立即加载
灵活性更灵活不灵活
SQL难易度简单复杂
选择依据简单、灵活高性能
立即加载

​ 运行时直接加载

接口

public interface DeptMapper {/*根据编号查询部门信息*/Dept getDeptByDeptno(int deptno);
}
public interface EmpMapper {/*根据编号查询部门员工信息*/List<Emp> getEmpByDeptno(int deptno);
}

实体类

public class Dept {private Integer deptno;private String dname;private String loc;private List<Emp> emps;public List<Emp> getEmps() {return emps;}public void setEmps(List<Emp> emps) {this.emps = emps;}
}public class Emp implements Serializable {private Integer empno;private String ename;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;
}

mapper映射文件

<mapper namespace="com.test.mapper.EmpMapper"><select id="getEmpByDeptno" resultType="emp">select * from emp where deptno=#{deptno};</select>
</mapper>  <mapper namespace="com.test.mapper.DeptMapper"><resultMap id="deptJoinEmp" type="dept"><id property="deptno" column="deptno"></id><result property="dname" column="dname"></result><result property="loc" column="loc"></result><collectionproperty="emps"ofType="emp"column="deptno"select="com.test.mapper.EmpMapper.getEmpByDeptno"fetchType="eager"/></resultMap><select id="getDeptByDeptno" parameterType="Dept" resultMap="deptJoinEmp">select * from dept where deptno=#{deptno}</select>
</mapper>

测试代码

public class Test1 {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);Dept dept = mapper.getDeptByDeptno(10);System.out.println(dept);List<Emp> empList = dept.getEmps();empList.forEach(System.out::println);}
}
延迟加载

​ 作用:延迟加载可以根据用的需求动态的决定查询数据的时机。

延迟加载可以理解为是级联查询的一种优化策略

​ 优点:可以将查询的工作量在时间上分散

​ 减少单位时间内对于数据库的查询次数,进而减少数据库单位时间的运算压力

​ 提高数据库响应速度

​ 级联查询将一个多表关联查询转换成多个单边查询,sql语句变得简单了,单次单表查 询比单次表查询效率更高,响应速度更快

延迟加载使用

第一步:全局开关:在mybatis.xml中打开延迟加载的开关

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

lazyLoadingEnabled:是否开启延迟加载。是Mybatis是否启用懒加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态

**aggressiveLazyLoading:**当开启时,任何方法的调用都会懒加载对象的所有属性。否则,每个属性会按需加载,

第二步:分开关:指定的association和collection元素中配置fetchType属性。eager:表示立刻加载;lazy:表示延迟加载。将覆盖全局延迟设置

​ 接口

public interface DeptMapper {/*根据编号查询部门信息*/Dept getDeptByDeptno2(int deptno);
}
public interface EmpMapper {/*根据编号查询部门员工信息*/List<Emp> getEmpByDeptno(int deptno);}

​ 实体类

public class Dept {private Integer deptno;private String dname;private String loc;private List<Emp> emps;public List<Emp> getEmps() {return emps;}public void setEmps(List<Emp> emps) {this.emps = emps;}
}public class Emp implements Serializable {private Integer empno;private String ename;private String job;private Integer mgr;private Date hiredate;private Double sal;private Double comm;private Integer deptno;
}

​ mybatis配置文件

 <!--设置延迟加载azyLoadingEnabled:是否开启延迟加载aggressiveLazyLoading:当开启时,任何方法的调用都会懒加载对象的所有属性--><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/>

​ mapper映射文件

<select id="getDeptByDeptno" resultMap="deptJoinEmp">select * from dept where deptno=#{deptno}</select><resultMap id="deptJoinEmp2" type="dept"><id property="deptno" column="deptno"></id><result property="dname" column="dname"></result><result property="loc" column="loc"></result><collectionproperty="emps"ofType="emp"column="deptno"select="com.test.mapper.EmpMapper.getEmpByDeptno"fetchType="lazy"/></resultMap><select id="getDeptByDeptno2" resultMap="deptJoinEmp2">select * from dept where deptno=#{deptno}</select>

测试代码

public class Test2 {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);Dept dept = mapper.getDeptByDeptno2(10);System.out.println(dept.getDname()+" "+dept.getLoc());List<Emp> emps = dept.getEmps();;emps.forEach(System.out::println);}
}

MyBatis注解开发

  • 使用注解没有实现java代码和SQL语句的解耦
  • 无法实现SQL语句的动态拼接
  • 进行多表的查询时定制resultMap比较麻烦

注解和XML的优缺点

XML注解
优点1.类和类之间的解耦 2.利于修改。直接修改XML文件,无需到源代码中修改。 3.配置集中在XML中,对象间关系一目了然,利于快速了解项目和维护 4.容易和其他系统进行数据交交换1.简化配置 2.使用起来直观且容易,提升开发效率 3.类型安全,编译器进行校验,不用等到运行期才会发现错误。 4.注解的解析可以不依赖于第三方库,可以之间使用Java自带的反射

接口

public interface EmpMapper {/*根据编号查询部门员工信息*/@Select(" select * from emp where deptno =#{deptno}")List<Emp> getEmpByDeptno(int deptno);@Select("select * from emp where empno =#{empno}")Emp getEmpByempNo(int empNo);@Insert("insert into emp values(null,#{ename},#{job},#{mgr}," +"#{hiredate},#{sal},#{comm},#{deptno})")int addEmp(Emp emp);@Update("update emp set ename=#{ename} where empno=#{empno}")int updateEmp(Emp emp);@Delete("delete from emp where empno=#{empno}")int deleteEmp(int empno);
}

测试代码

public class Test1 {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);//查询Emp emp = mapper.getEmpByempNo(1);System.out.println(emp);List<Emp> emps = mapper.getEmpByDeptno(10);emps.forEach(System.out::println);//添加Emp emp1 = new Emp(null,"liuxing","aaa",8989,new Date(),1000.0,1000.0,10);mapper.addEmp(emp1);//修改Emp emp2 = new Emp();emp2.setEmpno(1);emp2.setEname("小白");mapper.updateEmp(emp2);//删除mapper.deleteEmp(5);sqlSession.commit();sqlSession.close();}

no}

测试代码```java
public class Test2 {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession();DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);Dept dept = mapper.getDeptByDeptno2(10);System.out.println(dept.getDname()+" "+dept.getLoc());List<Emp> emps = dept.getEmps();;emps.forEach(System.out::println);}
}

MyBatis注解开发

  • 使用注解没有实现java代码和SQL语句的解耦
  • 无法实现SQL语句的动态拼接
  • 进行多表的查询时定制resultMap比较麻烦

注解和XML的优缺点

XML注解
优点1.类和类之间的解耦 2.利于修改。直接修改XML文件,无需到源代码中修改。 3.配置集中在XML中,对象间关系一目了然,利于快速了解项目和维护 4.容易和其他系统进行数据交交换1.简化配置 2.使用起来直观且容易,提升开发效率 3.类型安全,编译器进行校验,不用等到运行期才会发现错误。 4.注解的解析可以不依赖于第三方库,可以之间使用Java自带的反射

接口

public interface EmpMapper {/*根据编号查询部门员工信息*/@Select(" select * from emp where deptno =#{deptno}")List<Emp> getEmpByDeptno(int deptno);@Select("select * from emp where empno =#{empno}")Emp getEmpByempNo(int empNo);@Insert("insert into emp values(null,#{ename},#{job},#{mgr}," +"#{hiredate},#{sal},#{comm},#{deptno})")int addEmp(Emp emp);@Update("update emp set ename=#{ename} where empno=#{empno}")int updateEmp(Emp emp);@Delete("delete from emp where empno=#{empno}")int deleteEmp(int empno);
}

测试代码

public class Test1 {public static void main(String[] args) {SqlSession sqlSession = SqlSessionUtil.getSqlSession();EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);//查询Emp emp = mapper.getEmpByempNo(1);System.out.println(emp);List<Emp> emps = mapper.getEmpByDeptno(10);emps.forEach(System.out::println);//添加Emp emp1 = new Emp(null,"liuxing","aaa",8989,new Date(),1000.0,1000.0,10);mapper.addEmp(emp1);//修改Emp emp2 = new Emp();emp2.setEmpno(1);emp2.setEname("小白");mapper.updateEmp(emp2);//删除mapper.deleteEmp(5);sqlSession.commit();sqlSession.close();}
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 服务器每天都被攻击怎么解决

    9月下旬&#xff0c;媒体报道育碧旗下的战术射击游戏《彩虹六号&#xff1a;围攻》遭遇DDoS攻击&#xff0c;这次攻击导致对这款游戏的正常运营造成了干扰。 还记得8月底&#xff0c;经典游戏《魔兽世界》怀旧服一上线就人满为患。不到一周&#xff0c;几十万玩家登录不上游戏&…...

    2024/4/28 0:46:54
  2. java使用poi所需要的jar

    踩了半天的坑终于把java操作PPT的所有需要的jar给找齐了 csdn常见的回答 只包含poi 和 collection 经过测试明显不够 会报各种错误 根据csdn和错误分析 查了半天终于 能使用了 以下是导入的各种jar 其中可能有一些是不需要的我就懒得一个一个查了&#xff0c;但是全部导入是…...

    2024/5/4 0:04:15
  3. 2020-10-10分页效果

    PageList pl new PageList(hcpBadOrderList);ResultList resultList new ResultList();resultList.setRows(hcpBadOrderVoList);resultList.setPage(pl.getPage());resultList.setRecords(pl.getRecords());resultList.setTotal(pl.getTotal());return resultList;对于查询数…...

    2024/5/1 11:07:54
  4. Windows 撤销快捷键“ctrl+z“失效解决方法

    系统&#xff1a;windows10 问题&#xff1a;撤销快捷键失效 解决方案&#xff1a;导致问题的原因可能有好几种&#xff0c;我这种是由于搜狗输入法导致的&#xff0c;修改相应设置就好了。 打开控制面板——>搜“语言”&#xff0c;进入 2. 进入语言首选项 进入键盘设置…...

    2024/5/3 23:37:25
  5. 数字I/O设备 NI PXI-6527 二次软件开发手记

    NI Data Acquisition Devices NI PXI-6527 数字I/O设备 NI PXI-6527 PCI总线10, PCI设备12&#xff0c;功能0 简易控制流程&#xff08;VS2010&#xff09;: 1.程序设计界面 2.程序运行界面 3.主要程序 (1)打开 status viOpenDefaultRM ( &defaultRM ); status viOpen…...

    2024/4/28 19:36:44
  6. 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><!-- 环境配置 --><envi…...

    2024/4/29 20:56:05
  7. springMVC整合quartz 定时任务 怎么调用Controller...

    请问&#xff1a;springMVC整合quartz 定时任务 怎么调用Controller... 定时任务类加上Component注解并放入scan的package下&#xff0c;这样就可以在这个类里头直接Autowired 你想要的Controller了。或者全部用XML配置也行。 页面定义刷新逻辑。。定期请求数据。 Component…...

    2024/4/29 0:14:21
  8. 直播间人气软件

    ​抖音云控制有哪些功能&#xff1f; 精准养号功能&#xff1a;抖音广场筹集账户&#xff0c;同城养号&#xff0c;直播养号&#xff0c;垂直养号。 作品一键发布&#xff1a;您可以控制手机自动发布视频&#xff0c;或者将视频上传到系统以自动发送视频作品。——&#xff08;…...

    2024/4/8 1:35:17
  9. NPE问题

    最近在看Java_manual.pdf&#xff0c;其中有一点值得反思&#xff1a;“防止 NPE&#xff0c;是程序员的基本修养。” NPE(Null Pointer Exception)一直是我们最头疼的问题&#xff0c;也是最容易忽视的地方&#xff0c;先总结几条不同场景的解决方案&#xff0c;望后续补充。 …...

    2024/4/7 22:49:40
  10. ug建模教程ug建模怎么学ug10.0编程教程入门ug建模实例

    UG建模教程概述 中使用了UG软件的一个新指令“拔模”&#xff0c;具体操作步骤如下 UG建模步骤 1、绘制零件的底台&#xff1b;在草图中先画一个矩形&#xff0c;然后使用对称中心线命令&#xff0c;做到草图对称&#xff0c;然后再根据所绘图形的尺寸进行标注&#xff1b; …...

    2024/4/29 2:42:07
  11. 阿里云服务器防止ddos被攻击

    服务器被DDoS攻击最恶心&#xff0c;尤其是阿里云的服务器受攻击最频繁&#xff0c;因为黑客都知道阿里云服务器防御低&#xff0c;一但被攻击就会进入黑洞清洗&#xff0c;轻的IP停止半小时&#xff0c;重的停两个至24小时&#xff0c;给网站带来很严重的损失。 其实DDoS的核心…...

    2024/4/28 23:15:30
  12. 如何避免服务器被攻击

    前不久和小伙伴们讨论了一个基础的安全问题&#xff1a;一个朋友开的公司的服务器集群被黑了&#xff0c;攻击者在机器上安装了远程操作程序——被肉鸡了。但经过讨论后发现&#xff0c;机器的最基本的防护都没有。这无异于大姑娘在街上裸奔——就算长得再丑也最终会被爆的。本…...

    2024/4/24 19:45:55
  13. 养生小知识

    说到养生的话&#xff0c;一定要从饮食方面去做&#xff0c;可以多吃蔬菜水果,含有丰富的维生素等人体所需的矿物元素。可以逐渐的使身体得到优化。更有效的生活方式越强化身体的免疫系统&#xff0c;减少疾病.的发生,促进人的身体健康。 尤其是女性朋友,更应该注意养生。很多…...

    2024/4/28 9:03:34
  14. Spring Cloud分布式微服务实战 养成应对复杂业务的综合技术能力

    一课开发三大业务&#xff0c;打造企业级大型自媒体平台 囊括门户平台&#xff0b;媒体中心运营中心&#xff0c;好项目助力你全面成长进阶 明星讲师“风间影月”力作 后端主流技术综合应用 学员遍布各BAT大厂《Java架构师体系课》核心讲师 掌握Spring CloudMongoDBRedisR…...

    2024/4/19 5:41:04
  15. 服务器一直被ddos攻击怎么办

    一、分析一下ddos原因&#xff0c;是你的对手原因&#xff0c;还是你服务器原因&#xff0c; 比如以前容易被ddos的服务器一般是私服&#xff0c;赌博站&#xff0c;钓鱼站等非法站也容易被ddos. 二、有的说是ddos&#xff0c;有的技术人员没有分析出是cc还是真的ddos cc的一般…...

    2024/4/27 17:58:53
  16. DWSurvey是一个开源的调查问卷系统。解决无法运行问题,修改bug。

    DWSurvey是一个开源的调查问卷系统。 修复的问题 1、源项目启动后所有动态访问均报404问题 解决方案&#xff1a;降低struts版本&#xff0c;由struts2.5降至struts2.2.1 2、源项目退出操作无响应 原因&#xff1a;源项目中集成shiro后只处理了登录未处理退出 …...

    2024/5/2 20:35:02
  17. 详解Java8新特性

    详解Java8新特性1.简介2. 新特性2.1 Lambda表达式2.1.1 语法2.1.2 重要特征2.1.3 例子2.1.4 注意2.2 方法引用2.2.1 语法2.2.2 例子2.3 函数式接口2.3.1 定义与实现2.3.2 已存在的函数式接口2.4.默认方法2.4.1 语法2.4.2 例子2.5 Stream API2.5.1 生成流2.5.2 forEach2.5.3 map…...

    2024/5/2 16:52:01
  18. 【element-ui笔记】element中el-table(合计)计算指定列

    1.需求&#xff1a;我只需要前面三列的合计&#xff0c;最后一列不需要 找了很久&#xff0c;看到element-ui里面的show-summary方法&#xff0c;以及自定义的:summary-method&#xff0c;觉得很合适 以下是官网说明&#xff1a; 实现代码如下&#xff1a; <el-table:dat…...

    2024/4/25 3:07:11
  19. Java后端知识整理

    Spring Spring框架的七大模块 Spring Core&#xff1a;框架的最基础部分&#xff0c;提供 IoC 容器&#xff0c;对 bean 进行管理。 Spring Context&#xff1a;继承BeanFactory&#xff0c;提供上下文信息&#xff0c;扩展出JNDI、EJB、电子邮件、国际化等功能。 Spring DAO…...

    2024/5/2 16:36:49
  20. Linux内核(x86)入口代码模糊测试指南Part 1

    在本系列文章中&#xff0c;我们将为读者分享关于内核代码模糊测试方面的见解。 简介 对于长期关注Linux内核开发或系统调用模糊测试的读者来说&#xff0c;很可能早就对trinity&#xff08;地址&#xff1a;https://lwn.net/Articles/536173/&#xff09;和syzkaller&#x…...

    2024/4/27 20:37:52

最新文章

  1. 排序算法--直接选择排序

    前提&#xff1a; 选择排序&#xff1a;选择排序(Selection sort)是一种比较简单的排序算法。它的算法思想是每一次从待排序的数据元素中选出最小(或最大)的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完。 话不多说&#xff0c;直接放图…...

    2024/5/4 8:17:32
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. OpenCV单通道图像按像素成倍比例放大(无高斯平滑处理)

    OpenCV中的resize函数可以对图像做任意比例的放大(/缩小)处理&#xff0c;该处理过程会对图像做高斯模糊化以保证图像在进行放大&#xff08;/缩小&#xff09;后尽可能保留源图像所展现的具体内容&#xff08;消除固定频率插值/采样带来的香农采样信息损失&#xff09;&#x…...

    2024/5/1 13:33:49
  4. 微信小程序实现左滑删除

    效果 实现思路 使用的是官方提供的movable-area 嵌套movable-view 1、movable-area&#xff1a;注意点&#xff0c;需要设置其高度&#xff0c;否则会出现列表内容重叠的现象。 2、由于movable-view需要向右移动&#xff0c;左滑的时候给删除控件展示的空间&#xff0c;故 mov…...

    2024/5/1 13:30:10
  5. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/3 11:50:27
  6. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/2 16:04:58
  7. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/2 23:55:17
  8. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/3 16:00:51
  9. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/5/3 11:10:49
  10. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/3 21:22:01
  11. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/3 23:17:01
  12. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/2 23:47:43
  13. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/3 13:26:06
  14. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/3 1:55:15
  15. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/5/4 2:14:16
  16. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/3 16:23:03
  17. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/3 1:55:09
  18. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/2 8:37:00
  19. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/3 14:57:24
  20. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/2 9:47:25
  21. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/4 2:00:16
  22. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/3 22:03:11
  23. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/3 7:43:42
  24. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/3 1:54:59
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57