Mybatis | Mybatis的核心配置

目录:

  • Mybatis的核心配置 :
    • 一、MyBatis的 “核心对象”
      • 1.1 SqlSessionFactory
      • 1.2 SqlSession :
        • SqlSession对象中的操作数据库的方法 :
          • \<T> T selectOne ( String statement )
          • \<T> T selectOne( String statement , Object parameter )
          • \<E> List\<E> selectList ( String statement )
          • \<E> List\<E> selectList ( String statement , Object parameter )
          • \<E> List\<E> selectList ( String statement , Object parameter , RowBounds rowBounds )
          • void select ( String statement , Object parameter , ResultHandler handler )
          • int insert ( String statement )
          • int insert ( String statement , Object parameter )
          • int update( String statement )
          • int update( String statement , Object parameter)
          • int delete( String statement )
          • int delete( String statement , Object parameter)
          • int commit( )
          • void rollback( )
          • void close( )
          • \<T> T getMapper( Class\<T> type )
          • Connection getConnection( )
        • 使用工具类创建 “SqlSession” / SqlSession工具类
    • 二、MyBatis的 “配置文件”
      • “映射文件”中的 “主要元素”
        • \<properties>元素
        • \<settings>元素
        • \<typeAliases>元素
        • \<typeHandler>元素
        • \<objectFactory>元素
        • \<plugins>元素
        • \<environments>元素
        • \<mappers>元素
    • 三、MyBatis的 “映射文件”
      • “配置文件”中的 “主要元素”
        • \<select>元素
        • \<insert>元素
        • \<update>元素和\<delete>元素
        • \<sql>元素
        • \<resultMap>元素 (可解决“属性名” 和 “字段名”不一样导致的数据无法映射成功的问题)

Mybatis的核心配置 :

一、MyBatis的 “核心对象”

  • 在使用MyBatis框架时,主要涉及 两个核心对象 : SqlSessionFactorySqlSession,它们在MyBatis框架中起着至关重要作用

1.1 SqlSessionFactory

  • SqlSessionFactory是MyBatis 框架中十分重要对象,它是单个数据库映射关系经过编泽后内存镜像,其主要作用创建SqlSession

  • SqlSessionFactory 对象的实例可以通过 SqlSessionFactoryBuilder对象 来构建,而SqlSessionFactoryBuilder对象 则可以通过 XML配置文件 或一个预先定义好Configuration实例 构建出SqlSessionFactory实例

  • 以下内容讲解的是 :就是 通过XML配置文件 构建出的SqlSessionFactory实例,其实现代码如下:

    InputStream inputStream = Resources.getResourceAsStream("配置文件的位置");
    //通过SqlSessionFactoryBuilder的 build()方法 + 配置文件来创建 SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
  • SqlSessionFactory对象线程安全 的,它一旦被创建,在整个应用执行期间都会存在。如果我们多次地创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽。为了解决此问题,通常每一个数据库都会只对应一个 SqlSessionFactory, 所以在 构建SqlSessionFactory实例时,建议使用单列模式

1.2 SqlSession :

  • SqlSession 是MyBatis 框架中另一个重要对象, 它是 应用程序持久层之间执行与操作的一个单线程对象,其主要作用执行持久化操作

  • SqlSession对象包含数据库中所有执行SOL操作方法SqlSession中有很多操作数据库方法),由于其底层封装JDBC连接,所以可以直接使用SqlSession实例来 执行已映射SQL语句

    (可用SqlSession来执行 “映射文件” 中的sql语句)。

  • 每一个线程都应该有一个自己的SqlSession实例,并且该实例不能被共享的。同时,SqlSession实例线程不安全 的,因此 使用范围 最好在 一次请求一个方法 中,绝不能将其放在一个静态字段实例字段任何类型的管理范围 (如Servlet的HttpSession)中使用。

  • 使用完SqlSession对象之后,要及时地关闭它,通常可以将其放在fnally块中关闭

//通过 sqlSessionFactory对象获得"SqlSession"
SqlSession sqlSession = sqlSessionFactory.openSession();
try{//此处执行持久化操作
}finally{sqlSession.close();
}
SqlSession对象中的操作数据库的方法 :
<T> T selectOne ( String statement )

<T> T selectOne ( String statement ) : 查询方法 : 参数 statement 是在 “ 映射文件 中定义的 <select>元素id
目的是 : 获得映射文件中的 “<select>元素下所代表的 sql语句 作为selectOne( )方法的参数 ”)。使用该方法后,会返回执行SQL语句查询结果一条泛型对象

<T> T selectOne( String statement , Object parameter )

<T> T selectOne ( String statementObject parameter ) :查询方法 : 参数 statement 是在 “ 映射文件 中定义的 <select>元素idparameter查询所需参数。使用该方法后,会返回执行SQL语句查询结果一条泛型对象

<E> List<E> selectList ( String statement )

<E> List<E> selectList ( String statement ) : 查询方法 : 参数 statement 是在 “映射文件” 中定义的 <select>元素id 。使用该方法后,会返回执行SQL语句查询结果泛型对象集合

<E> List<E> selectList ( String statement , Object parameter )

<E> List<E> selectList ( String statement , Object parameter ) : 查询方法 : 参数 statement 是在 “ 映射文件” 中定义的 <select>元素id , parameter 是查询所需的参数。使用该方法后,会返回执行SQL语句查询结果的 泛型对象集合

<E> List<E> selectList ( String statement , Object parameter , RowBounds rowBounds )

<E> List<E> selectList ( String statement , Object parameter ) : 查询方法 : 参数==statement==是在 “ 映射文件” 中定义的 <select>元素id , parameter 是查询所需的参数,rowBounds是用于分页参数对象。使用该方法后会返回执行SQL语句查询结果的 泛型对象集合

void select ( String statement , Object parameter , ResultHandler handler )

void select ( String statement, Object parameter,ResultHandler handler ) : 查询方法 : 参数statement是在配置文件中定义的 <select>元素idparameter 是查询所需的 参数ResultHandler对象用于处理查询返回复杂结果集。 (通常用于多表查询

int insert ( String statement )

int insert ( String statement ) : 插入方法 : 参数 statement是在 “映射文件” 中定义的 <select>元素id ,使用该方法后,会返回执行 SQL语句所影响行数

int insert ( String statement , Object parameter )

int insert ( String statement , Object parameter ) : 插入方法 : 参数 statement 是在 “ 映射文件” 中定义的 <select>元素idparameter 是查询所需的参数。使用该方法后,会返回执行 SQL语句所影响行数

int update( String statement )

int update ( String statement ) : 更新方法 : 参数 statement 是在 “ 映射文件” 中定义的 <update>元素id ,使用该方法后,会返回执行 SQL语句所影响行数

int update( String statement , Object parameter)

int update ( String statement , Object parameter ) : 更新方法 : 参数 statement 是在 “ 映射文件” 中定义的 <update>元素idparameter更新所需的参数。使用该方法后,会返回执行 SQL语句所影响行数

int delete( String statement )

int delete ( String statement ) : 删除方法 : 参数 statement 是在 “映射文件” 中定义的 <delete>元素id ,使用该方法后,会返回执行 SQL语句所影响行数

int delete( String statement , Object parameter)

int delete ( String statement , Object parameter ) : 删除方法 : 参数 statement 是在 “ 映射文件” 中定义的 <delete>元素idparameter删除所需的参数使用该方法后,会返回执行 SQL语句所影响行数

int commit( )

int commit ( ) : 提交事务方法

void rollback( )

int rollback ( ) : 回滚事务方法

void close( )

int close ( ) : 关闭SqlSession 对象。

<T> T getMapper( Class<T> type )
  • <T> T getMapper ( Class<T> type ) : 该方法会返回 Mapper接口代理对象,该对象关联了SqlSession对象,开发人员可以使用对象直接调用方法操作数据库。参数type是Mapper的接口类型。MyBatis官方推荐通过
    Mapper对象访问MyBatis
  • 该方法 : getMapper( ) 的目的是根据传入的 类类型type 返回一个与该类型匹配的对象。具体实现可能涉及反射机制,用于 创建并返回一个与传入类类型相匹配实例
Connection getConnection( )

Connection getConnection( ) : 获取 JDBC数据库连接对象 的方法。

使用工具类创建 “SqlSession” / SqlSession工具类
  • 使用工具类创建 SqlSession对象 :

    package com.myh.utils;import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
    import java.io.InputStream;/*** 工具类*/
    public class SqlSessionUtils {  //获得SqlSession的"工具类"private static SqlSessionFactory sqlSessionFactory = null;//初始化 SqlSessionFactory 对象static { //静态代码块try {//使用Mybatis提供的Resources类加载mybatis-config.xml配置文件InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");//构建SqlSessionFactory工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}/*** 获得SqlSession对象的静态方法*/public static SqlSession getSession() {return sqlSessionFactory.openSession();}
    }
    

    这样,我们在使用时就 只创建了一个SqlSessionFactory 对象,并且可以通过工具类getSession( ) 方法, 来 获取SqlSession对象

二、MyBatis的 “配置文件”

MyBatis的核心配置文件中,包含了很多影响MyBatis行为的重要信息。这些信息通常在一个项目中只会在一个配置文件中编写,并且编写后也不会轻易改动。

“映射文件”中的 “主要元素”

  • MyBatis 框架的 核心配置文件 (即 mybatis-config.xml )中,<configuration> 元素 是配置文件的 根元素其他元素都要在 <configuration> 元素内配置。

  • Mybatis配置文件主要元素图 :(要熟悉 <configuration>元素各个子元素配置。)

    在这里插入图片描述

    ps :
    ==<Cofgnaion>子元素必须按照图中由上到下==的顺序进行配置,否则Mybatis在解新xml配置文件的时候会报错。

<properties>元素
  • <properties>是一个配置属性元素,该元素通常用于内部配置 “外在化”,即通过外部的配置来动态地替换内部定义的属性

(直接的使用 : 将外部的 Xxx.properties文件中的属性用于 mybatis配置文件中 )。
例如,数据库的连接等属性,就可以通过典型的 Java属性文件 ( .properties文件 )中的配置替换

ps :
当我们在mybatis配置文件中 使用 <properties>元素导入 .properties文件时,即可在mybatis配置文件中,即直接使用 .properties文件中的数据

db.properties

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

mybatis-config.xml

<?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><!-- properties属性 --><!-- 通过properties属性引入 .properties配置文件, mybatis配置文件中则可直接使用 .properties中的数据,进行"动态替换"  --><properties resource="db.properties"/><!-- environments属性 --><environments default="mysql"><environment id="mysql"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--通过“properties属性”来将 以下的driver、url、username、password 和.properties配置文件 中的数据进行“动态替换”--><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments></configuration>

完成上述配置后,dataSource中连接数据库的4个属性 ( driverurlusermamepassword值将会由db.properties文件对应的值动态替换。这样就为配置提供了诸多灵活的选择。
除了可以像上述通过外部配置文件定义属性值外,还可以通过配置 <properties>元素的子元素 <property>,以及通过方法参数传递的方式来获取属性值。由于使用properties配置文件来配置属性值可以方便地多个配置文件使用这些属性值,并且方便日后的维护和修改,所以在实际开发中,使用.properties文件来配置属性值最常用的方式

<settings>元素
  • <settings>元素主要用于改变MyBatis运行时行为,例如 开启二级缓存开启延迟加载 等。
    虽然不配置<settings>元素,也可以正常运行MyBatis, 但是熟悉<settings>的配置内容以及它们的作用还是十分必要的。

  • 常见的**<settings>属性配置在 “配置文件” 中的使用** :

        <settings><setting name="cacheEnabled" value="true" /><setting name="lazyLoadingEnabled" value="true" /><setting name="multipleResultSetsEnabled" value="true"/><setting name="useColumnLabel" value="true"/><setting name="useGeneratedKeys" value="false" /><setting name="autoMappingBehavior" value="PARTIAL"/>.....</settings>
    
<typeAliases>元素
  • <typeAliases>元素 用于为配置文件中的Java类型设置一个简短的名字,即 设置别名别名的设置与XML配置相关,其使用的意义在于减少全限定类名冗余。 如 : 可用 <typeAliases>元素POJO类设置一个 “别名

    <?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><!--  定义别名  --><typeAliases><!-- typeAlias元素 为 typeAliases元素的 "子元素"  --><typeAlias alias="user" type="com.myh.po.Customer"/></typeAliases></configuration>
    

    上述示例中,<typeAliases> 元素子元素 <typeAlias> 中的type属性用于指定需要被定义别名的类的全限定名alias属性的属性值user 就是自定义的别名,它可以代替com.myh.po.Customer使用在MyBatis文件任何位置如果省略alias属性,MyBatis 会默认将类名首字母 小写后的名称作为别名

  • POJO类过多,还可以通过自动扫描包形式自定义别名 (此时以类名首字母小写后的名称为 “别名”),具体示例如下 :

    <?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><!--  定义别名  --><typeAliases><!--   使用自动扫描包来定义“别名”  --><!--   Mybatis会将所用 com.myh.po包中POJO类以首字母小写的名称 作为“别名” --><!--   如: Customer 的 默认设置的别名为: customer  --><package name="com.myh.po"/></typeAliases></configuration>
    
  • 需要注意的是,上述方式的别名只适用于没有使用注解的情况。如果在程序中使用了注解,则别名其注解的值, 具体如下 :

    //使用注解来为该POJO类设置在 mybatis-config.xml配置文件中使用的 "别名"
    @Alias(value = "customer")
    public class Customer {  .....
    }
    
  • 除了可以使用 <typeAliases>元素自定义别名外,MyBatis框架还默认为许多常见的Java类型(如数值字符串日期集合等 )提供了 相应的类型别名。(可使用时查询常见的Java类型别名是什么

<typeHandler>元素
  • MyBatis预处理语句( PreparedStatement )中 设置一个参数或者从结果集 ( ResultSet )中取出一个值 时,都会用其框架内部注册了的 typeHandler ( 类型处理器 ) 进行相关处理

  • typeHandler作用就是将预处理语句 中传入的参数从 javaType ( Java类型) 转换为 jdbcType
    ( JDBC类型),或者从数据库取出结果时将 jdbcType 转换为 javaType

  • 为了方便转换,Mybatis框架提供了一系列默认的类型处理器

    类型处理器Java 类型JDBC 类型
    BooleanTypeHandlerjava.lang.Boolean, boolean数据库兼容的 BOOLEAN
    ByteTypeHandlerjava.lang.Byte, byte数据库兼容的 NUMERIC 或 BYTE
    ShortTypeHandlerjava.lang.Short, short数据库兼容的 NUMERIC 或 SMALLINT
    IntegerTypeHandlerjava.lang.Integer, int数据库兼容的 NUMERIC 或 INTEGER
    LongTypeHandlerjava.lang.Long, long数据库兼容的 NUMERIC 或 BIGINT
    FloatTypeHandlerjava.lang.Float, float数据库兼容的 NUMERIC 或 FLOAT
    DoubleTypeHandlerjava.lang.Double, double数据库兼容的 NUMERIC 或 DOUBLE
    BigDecimalTypeHandlerjava.math.BigDecimal数据库兼容的 NUMERIC 或 DECIMAL
    StringTypeHandlerjava.lang.StringCHAR, VARCHAR
    ClobReaderTypeHandlerjava.io.Reader-
    ClobTypeHandlerjava.lang.StringCLOB, LONGVARCHAR
    NStringTypeHandlerjava.lang.StringNVARCHAR, NCHAR
    NClobTypeHandlerjava.lang.StringNCLOB
    BlobInputStreamTypeHandlerjava.io.InputStream-
    ByteArrayTypeHandlerbyte[]数据库兼容的字节流类型
    BlobTypeHandlerbyte[]BLOB, LONGVARBINARY
    DateTypeHandlerjava.util.DateTIMESTAMP
    DateOnlyTypeHandlerjava.util.DateDATE
    TimeOnlyTypeHandlerjava.util.DateTIME
    SqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMP
    SqlDateTypeHandlerjava.sql.DateDATE
    SqlTimeTypeHandlerjava.sql.TimeTIME
    ObjectTypeHandlerAnyOTHER 或未指定类型
    EnumTypeHandlerEnumeration TypeVARCHAR 或任何兼容的字符串类型,用来存储枚举的名称(而不是索引序数值)
    EnumOrdinalTypeHandlerEnumeration Type任何兼容的 NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值(而不是名称)。
    SqlxmlTypeHandlerjava.lang.StringSQLXML
    InstantTypeHandlerjava.time.InstantTIMESTAMP
    LocalDateTimeTypeHandlerjava.time.LocalDateTimeTIMESTAMP
    LocalDateTypeHandlerjava.time.LocalDateDATE
    LocalTimeTypeHandlerjava.time.LocalTimeTIME
    OffsetDateTimeTypeHandlerjava.time.OffsetDateTimeTIMESTAMP
    OffsetTimeTypeHandlerjava.time.OffsetTimeTIME
    ZonedDateTimeTypeHandlerjava.time.ZonedDateTimeTIMESTAMP
    YearTypeHandlerjava.time.YearINTEGER
    MonthTypeHandlerjava.time.MonthINTEGER
    YearMonthTypeHandlerjava.time.YearMonthVARCHAR 或 LONGVARCHAR
    JapaneseDateTypeHandlerjava.time.chrono.JapaneseDateDATE
  • MyBatis框架所提供的 这些类型处理器不能够满足需求时,还可以通过自定义的方式对类型处理器进行扩展 ( 自定义类型处理器可以通过实现TypeHandler 接口 或者 继承 BaseTypeHandle类来定义)。

    <typeHandler> 元素就是用于在配置文件注册自定义类型处理器的。它的使用方式有两种
    注册一个类类型处理器
    注册一个包所有类型处理器

    CustomertypeHandler.java

    package com.myh.type;import org.apache.ibatis.type.JdbcType;
    import org.apache.ibatis.type.TypeHandler;import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    public class CustomertypeHandler implements TypeHandler {@Overridepublic void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {} @Overridepublic Object getResult(ResultSet rs, String columnName) throws SQLException {return null;}@Overridepublic Object getResult(ResultSet rs, int columnIndex) throws SQLException {return null;}@Overridepublic Object getResult(CallableStatement cs, int columnIndex) throws SQLException {return null;}
    }
    

    mybatis-config.xml

         <!-- 注册一个类的类型处理器 --><typeHandlers><!--  以单个类的形式配置   --><typeHandler handler="com.myh.type.CustomertypeHandler"/></typeHandlers><!-- 注册一个包中所有类的类型处理器 --><typeHandlers><!--  注册一个包中所有的typeHandler,系统在启动时会自动扫描包下的所有文件  --><package name="com.myh.type"/></typeHandlers>
    
<objectFactory>元素
  • MyBatis框架每次创建 结果对象新实例 时,都会使用一个对象工厂( ObjectFactory )的实例来完成。MyBatis中默认的 ObjectFactory的作用 就是 实例化目标类,它既可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化

  • 在通常情况下, 我们使用默认的ObjectFactory即可,MyBatis 中默认ObjectFactory是由org.apache.ibatis rflection.factory.DefaultObjectFactory来提供服务的。大部分场景下都不用配置和修改,但如果想覆盖ObjectFactory的默认行为,则可以通过自定义ObjectFactory来实现。

    MyObjectFactory.java

    package com.myh.objFactory;import org.apache.ibatis.reflection.factory.DefaultObjectFactory;import java.util.List;
    import java.util.Properties;//自定义工厂类 : 该类可以实现ObjectFactory接口 或 继承 DefaultObjectFactory类
    public class MyObjectFactory extends DefaultObjectFactory { //要继承DefaultObjectFactory类private static final long serialVerSionUID = -4114845625429965832L;@Overridepublic <T> T create(Class<T> type) {return super.create(type);}@Overridepublic <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {return super.create(type, constructorArgTypes, constructorArgs);}@Overridepublic void setProperties(Properties properties) {super.setProperties(properties);}@Overridepublic <T> boolean isCollection(Class<T> type) {return super.isCollection(type);}
    }
    

    mybatis-config.xml

    <?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><objectFactory type="com.myh.objFactory.MyObjectFactory"><property name="name" value="MyObjectFactory"/></objectFactory></configuration>
    
<plugins>元素
  • MyBatis允许在已映射语句执行过程中某一点进行拦截调用,这种拦截调用是通过插件来实现的。<plugins> 元素作用就是配置用户所开发插件。如果用户想要进行插件开发,必须要先了解其内部运行原理,因为在试图修改或重写已有方法的行为时,很可能会破坏MyBatis原 有的核心模块。
<environments>元素
  • 配置文件中,<environments>元素用于对环境进行配置MyBatis环境配置 实际上就是 数据源的配置,我们可以通过 <environments>元素配置多种数据源,即配置多种数据库

       <!-- environments属性 --><environments default="mysql"><environment id="mysql"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--通过“properties属性”来将 以下的driver、url、username、password 和.properties配置文件 中的数据进行“动态替换”--><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments>
    

    在上述代码中,<environments>元素环境配置根元素,它包含个一default属性,该属性用于指定默认环境ID。 是 <environments>元素的 “子元素”, : <environment> 可以定义多个,其记属性用于表示所定义环境ID值。在 environment元素内,包含事务管理 ( transactionManager ) 和 数据源 ( dataSource ) 的配置信息,其 <transactionManager>元素用于配置事务管理,它的type属性用于指定事务管理的方式,即使用哪种事务管理器<dalaSource>元素用于配置数据源,它的type属性用于指定使用哪种数据源

    在MyBatis中,可以配置两种类型的事务管理器,分别是 JDBCMANAGEDJDBC : 此配置直接使用了JDBC提交回滚设置,它依赖于从数据源得到的连接来管理事务作用域
    MANAGED : 此配置从来不提交回滚一个连接 ,而是让容器来管理事务整个生命周期
    默认情况下,它会关闭连接,但一些容器并不希望这样,为此可以将closeConnection属性
    置为false阻止它默认关闭行为

    ps :
    如果没有必要中 使用的是 Spring+ MyBatis,则 没有必要 在MyBatis ( mybatis-config.xml ) 中 配置事务管理器,因为实际开发中,会使用Spring自带的管理器实现事务管理

<mappers>元素
  • 配置文件 ( mybatis-config.xml )中,<mappers>元素 用于 指定MyBatis 映射文件 (引入“映射文件”)(XxxMapper.xml )的 位置,一般可以使用以下 4种方法 引入映射文件。 ( 一个mybatis-config.xml 配置文件可以引入多个“映射文件”。)

    使用 “类路径” 引入
    使用 “本地文件路径” 引入
    使用 “接口类” 引入
    使用 “包名” 引入

  • 使用 “类路径” 引入

    <mappers><!-- 使用"类路径"读取"映射文件" --><mapper resource="com/myh/mapper/CustomerMapper.xml"/>
    </mappers>
    
  • 使用 “本地文件路径” 引入

     <mappers><!--  使用“本地文件路径”引入“映射文件”  --><mapper url="file:///D:/com/myh/mapper/CustomerMapper.xml"/></mappers>
    
  • 使用 “接口类” 引入

    <mappers><!--  使用“接口类”引入“映射文件”  --><mapper class="com.myh.mapper.CustomerMapper"/>
    </mappers>
    
  • 使用 “包名” 引入

    <mappers><!-- 使用“包名”引入“映射文件” --><package name="com.myh.mapper"/>
    </mappers>
    

三、MyBatis的 “映射文件”

  • 映射文件 ( XxxMapper.xml )是Mybatis框架中十分重要的文件,可以说,Mybatis框架的强大之处就体现在“映射文件”的编写上
  • 映射文件中,<mapper>元素映射文件根元素,其他元素都是它的子元素
    在这里插入图片描述

“配置文件”中的 “主要元素”

<select>元素
  • <select>元素 用于映射 “查询语句”,它可以帮助我们从数据库中读出数据,并组装数据给企业开发者。

        <!-- “查询数据”--><select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer">select * from t_customer where id = #{id}</select>
    

    上述语句中的唯一标识为 findCustomerByld,它接收一个 Integer 类型参数,并返回一个Customer类型对象

  • <select>元素中,除了上述代码中的几个属性还有其他一些可以配置属性如下所示

    属性说明
    id表示命名空间中唯一标识符, 常与命名空间组合起来使用组合后如果不唯一, MyBatis会抛出异常。
    parameterType该属性表示传入SQL语句参数类全限定名或者别名。它是一个可选属性, 因为MyBatis可以通过TypeHandler推断出具体传入语句参数。其默认值是unset (依赖于驱动)
    resultType从SQL语句中返回的类型全限定名或者别名。如果是集合类型,那么返回的应该是集合可以包含类型,而不是集合本身。返回时可以使用resultTyperesultMap之一。
    resultMap表示外部resultMap命名引用。返回时可以使用resultTyperesultMap之一。
    flushCache表示在调用SQL语句之后,是否需要MyBatis清空之前查询本地缓存二级缓存。其值为布尔类型( truelfalse),默认值为false。如果设置为true,则任何时候只要SQL语句被调用,都会清空本地缓存二级缓存。
    useCache用于控制二级缓存开启关闭。其值为布尔类型( truelfalse),默认值为true,表示将查询结果存入二级缓存中。
    timeout用于设置超时参数,单位为超时将抛出异常
    fetchSize获取记录总条数设定,其默认值是unset (依赖于驱动)。
    statementType用于设置MyBatis使用哪个JDBCStatement工作,其值为STATEMENTPREPARED(默认值)CALLABLE, 分别对应JDBC中的StatementPreparedStatementCallableStatement
    属性说明
    resultSetType表示结果集类型,其值可设置为FORWARD_ONLY、SCROLL_SENSITIVE 或SCROLL_INSENSITIVE, 它的默认值是unset (依赖于驱动)
<insert>元素
  • <insert>元素用于映射“插入语句,在执行完元素中定义的SQL语句后,返回一个表示插入记录数整数
<!--useGeneratedKeys="true" : 获得该insert语句插入数据库时形成的“主键id” / 获得数据库内部产生的主键idkeyProperty="id" : 将插入或更新时的“返回值”赋值到PO类的对应的“属性”上 : 即将刚获得的“主键id”赋值到PO类对应的id属性上-->
<!--  该insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id  -->
<insert id="addCustomer" parameterType="com.myh.po.Customer"flushCache="true" statementType="PREPARED"keyProperty="id" keyColumn="" useGeneratedKeys="true" timeout="20">insert into t_customer(username,jobs,phone)values(#{username},#{jobs},#{phone})
</insert>

以上的 insert语句返回值 : ①返回插入成功的行数 ②插入行的主键id
上述代码中可以看出,<insert>元素属性<select>元素属性大部分相同<insert>元素包含了 3个特有属性

  • <insert>元素 中的三个特有 属性 :
属性说明
keyProperty( 仅对insert和update有用 )此属性 ( keyProperty )的作用插入 或 更新操作时返回值赋值给 PO类某个属性通常会设置为“主键”对应的属性
(通常会设置该属性的值为“id” (即将插入形成的“主键id”值赋值到PO类中 )。如果需要设置联合主键,可以在多个值之间用逗号隔开
例子如 :
keyProperty =“i‘d” ( 要结合useGeneratedKeys属性使用 ) :
useGeneratedKeys属性获得的 ( 插入形成的 ) “主键id” 赋值到PO类的对应的id属性上,这样就能获得insert语句生成的数据对应的“主键id”了。
keyColumn( 仅对insertupdate有用 ) 此属性用于 设置第几列主键主键列不是表中第一列时需要设置,在需要主键联合时,值可以使用逗号隔开。
useGeneratedKeys( 仅对insertupdate有用 )此属性会使 MyBatis 使用 JDBCgetGeneratedKeys( )方法来获取由数据库内部生产主键 (此时一般配合keyProperty属性使用来将该“主键 赋值给PO类对应的属性上。”), 如MySQLSQL Server自动递增字段,其 默认值false

执行插入操作后,很多时候我们会需要返回插入成功数据生成主键值 ( 表中主键id ),此时就可以通过
上面所讲解的3个属性来实现。


  • 如果使用的数据库支持主键自动增长 (如MySQL ),那么可以通过keyProperty属性 指定PO类某个属性接收主键返回值 ( 通常会设置到id属性上 : 将主键id赋值给PO类id属性上 ),同时还要通过 useGeneratedKeys属性才能实现目标功能。 例子如下 :

<insert>元素 中的三个特有 属性 例子如 :

CustomerMapper.xml (映射文件) :

<!--useGeneratedKeys="true" : 获得该insert语句插入数据库时形成的“主键id” / 获得数据库内部产生的主键idkeyProperty="id" : 将插入或更新时的“返回值”赋值到PO类的对应的“属性”上 : 即将刚获得的“主键id”赋值到PO类对应的id属性上-->
<!--  该insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id  -->
<insert id="addCustomer" parameterType="com.myh.po.Customer"keyProperty="id"  useGeneratedKeys="true" >insert into t_customer(username,jobs,phone)values(#{username},#{jobs},#{phone})
</insert>

以上的 insert语句返回值 : ①返回插入成功的行数 ②插入行的主键id

CustomerTest.java (测试类) :

public class CustomerTest {@org.junit.Test //单元测试public void addCustomerTest() throws IOException {//1.读取mybatis框架的配置文件String resource = "com/myh/映射文件的元素/mybatis-config.xml";//通过“输入流”读取mybatis配置文件/*在该mybatis-config.xml配置文件中,已配置了“数据源”信息 和配置了"映射文件 : XxxMapper.xml”的位置,可实施加载“映射文件”*/InputStream inputStream = Resources.getResourceAsStream(resource);//2.根据配置文件“构建会话工厂 : SqlSessionFactory ”SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//3.通过SqlSessionFactory(会话工厂)创建SqlSession("会话"对象)SqlSession sqlSession = sqlSessionFactory.openSession();Customer customer = new Customer();customer.setUsername("小蓝");customer.setJobs("学生");customer.setPhone("12345678");//将该Customer对象存入到数据库中,同时目的是: 将存入到数据库中的数据对应的“主键id”获得且返回int insert = sqlSession.insert("CustomerMapper.addCustomer", customer);/*** 输出"插入数据"形成的"主键id值"  (从数据库中获得的主键id值是存储在Customer这个PO类中的)*/System.out.println(customer.getId());if (insert > 0) {System.out.println("你成功插入了" + insert + "条数据!");} else {System.out.println("插入数据操作失败! ");}//4.设置“事务管理”sqlSession.commit();//5.关闭SqlSessionsqlSession.close();}
}

通过上述的<insert>元素三个特有属性,即可获得插入数据对应“ 主键id”

在这里插入图片描述


  • 如果使用的数据库不支持主键自动增长 (如Oracle ), 或者支持增长的数据库 取消了主键自增 的规则时,也可以使用MyBatis提供的另一种方式自定义生成主键例子如下

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--映射文件中,插入数据用 <insert>元素
    -->
    <!-- #{} : 相当于"占位符"  ${} : 相当于在sql语句后要拼接的"字符串" -->
    <mapper namespace="CustomerMapper"><insert id="insertCustomer" parameterType="com.myh.po.Customer"><selectKey keyProperty="id" resultType="Integer" order="BEFORE">select if(max(id) is null,1,max(id) + 1)as newId from t_customer</selectKey>insert into t_customer(username,jobs,phone)values(#{username},#{jobs},#{phone})</insert></mapper>
    

    上述代码中,<selectKey> 元素会首先运行,它会通过自定义的语句来设置数据中的主键 (如果
    t_customer表中没有记录,则将id设置为1,否则就将id的最大值加1,来为新的主键),然后再调用插入语句
    <selectKey>元素在使用时可以设置以下几种属性

    <selectKeykeyProperty="id"resultType="Integer"order="BEFORE"statementType="PREPARED">
    

    在上述 <selectKey>元素的几个属性中,keyPropertyresultTypestatementType的作用与前面讲解的相同,order 属性可以被设置为BEFOREAFTER如果设置BEFORE,那么它会首先执行 <selectKey>元素中的配置设置主键,然后执行插入语句;如果设置为AFTER,那么它会先执行插入语句,然后执行 <selectKey>元素中的配置内容。

<update>元素和<delete>元素
  • <update><delete>元素 的使用比较简单,它们的属性配置也基本相同 ,其常用属性如下 :
  <!-- 更新 --><update id="updateCustomer" parameterType="com.myh.po.Customer"flushCache="true" statementType="PREPARED" timeout="20"></update><!-- 删除 --><delete id="deleteCustomer" parameterType="com.myh.po.Customer"flushCache="true" statementType="PREPARED" timeout="20"></delete>

从上述配置代码中可以看出,<update><delete>元素属性基本与 <select>元素中属性一致
<insert>元素一样,<update> 和<delete>元素在执行完之后,也会返回一个表示影响记录条数整数,其使用示例如下 :

<!-- 更新 -->
<update id="updateCustomer" parameterType="com.myh.po.Customer">update t_customer set username = #{username},jobs=#{jobs},phone=#{phone}where id = #{id}</update><!-- 删除 --><delete id="deleteCustomer" parameterType="Integer">delete from t_customer where id = #{id}</delete>
<sql>元素
  • 一个映射文件中,通常需要定义多条SQL语句,这些SQL语句的组成可能有一部分是相同的 ( 如多条select语句中都查询相同的idusernamejobs 字段),如果每一个SQL语句都重写遍相同的部分, 势必会增加代码量,导致映射文件过于臃肿

  • 那么有没有什么办法将这些SQL语句相同组成部分抽取出来,然后在需要的地方引用呢 ?
    答案是肯定的,我们可以在映射文件中使用MyBatis所提供的 <sql>元素来解决上述问题。<sql>元素的作用 : 就是定义可重用SQL代码片段,然后在其他语句中引用这一代码片段

    例子如

     <sql id="customerColumns"> id,username,jobs,phone</sql><select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer">select <include refid="customerColumns"/>from t_customerwhere id = #{id}</select>
    
<resultMap>元素 (可解决“属性名” 和 “字段名”不一样导致的数据无法映射成功的问题)
  • <resultMap>元素表示结果映射集,是 MyBatis最重要 也是 最强大元素。它的主要作用 : 是
    定义映射规则级联的更新 以及 定义类型转化器 等。

    ps :
    <resultMap>元素 可解决“属性名” 和 “字段名不一样导致的数据无法映射成功问题

  • <resutMap>元素中包含了属性 / 子元素,如下所示 :

       <!--  resultMap的元素结构  --><resultMap type="" id=""><constructor>  <!-- 类在实例时,用来注入"结果"到"结构方法"中 --><idArg/>    <!-- ID参数;标记结果为ID --><arg/>     <!-- 注入到构造方法的一个普通结果 --></constructor><id/>          <!-- 用于表示哪个"列"是"主键" --><result/>      <!-- 注入到“字段”或“JavaBean属性”的普通结果 --><association property=""/>  <!-- 用于一对一关联 --><collection property=""/>   <!-- 用于一对多关联 --><discriminator javaType="">   <!-- 使用"结果值"来决定哪个"结果映射"--><case value=""></case></discriminator></resultMap>
    
  • <resutMap>元素属性 关系如下表所示 :

    属性描述
    type表示需要 映射 POJO ( 普通Java对象 )
    id这个 resultMap唯一标识
  • <resutMap>元素子元素 关系如下表所示 :

    子元素描述
    <constructor>用于配置构造方法 ( 当一个POJO未定义无参构造方法时,就可以使用 <constructor>元素 进行配置)。
    <id>分别标记 POJO中属性中的“主键和 标记数据库表中字段的 “主键,并 将二者进行关联
    ps :
    这意味着,通过 <resultMap> 中的 <id>元素的配置,POJO“主键”属性名 不用 和数据库中 “主键”名相同。
    <result>表示 POJO属性数据库表映射关系。(用于POJO中 “属性数据库表中的 “进行关联。 )
    ps :
    这意味着
    ,通过 <resultMap> 中的 <result>元素的配置,数据库中的 “字段” 以及 该“字段”相对应的 “属性”名,不用一致。(在 <result>中设置各自的名称即可)
    <association>表示“一对一”关联。用于处理“多表”时的关联关系
    <collection>表示“一对多”关联。用于处理“多表”时的关联关系
    <discriminator>使用"结果值"来决定哪个"结果映射"用于处理一个单独的数据库查询 返回很多不同数据类型 结果集情况
  • 在默认情况下,MyBatis程序在运行时会 自动地将查询到数据与需要返回的对象属性进行匹配赋值 ( 需要表中的 列名与对象的属性名称完全一致 )。 然而实际开发时,数据表中的和需要返回的对象的属性可能不会完全一致, 这种情况下MyBatis是不会自动赋值。此时,就可以使用 <resultMap>元素进行处理

  • 实际开发中,如果当POJO中“属性名” 和 数据库中“字段名不一致,此时查询数据库,数据会无法映射到POJO类中,最后导致查询到的内容为null。 此时<resultMap>元素即可解决这个问题

    例子如:
    在这里插入图片描述

    在这里插入图片描述


    此时可使用“映射文件” 中的因属性名 和 字段名不一致导致的数据无法映射POJO中的问题。如下所示 :

    UserMapper.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="UserMapper"><!--  select元素中使用resultType时,当数据库中"字段名" 和POJO中"属性名"不一致时,select的数据将则无法映射到POJO类中,即输出内容为null --><!--  select元素中用resultMap时,数据库中“字段名” 和 POJO中“属性名”不用保持一致,此时也能完成将select到的数据映射到POJO类中--><select id="selectUser_resultType" resultType="com.myh.po.User" parameterType="Integer">select * from t_user where t_id = #{id}</select><!--上面这个select的查询的数据是无法映射到POJO类中,即select的数据为null,因为数据库中“字段名” 和 POJO中的“属性名”,此时可用 <resultMap>元素来解决这个问题 --><resultMap id="resultMap" type="com.myh.po.User"><!--   下面配置的目的 : "属性名" 和 "字段名" 可以不用保持一致   --><id property="id" column="t_id"/><result property="name" column="t_name"/><result property="age" column="t_age"/></resultMap><!--  因为此处用了resultMap(已经配置好了,完成各种内容的“映射了”,所以即使"属性名" 和 “字段名”不一致,也能select到数据)  --><select id="selectUser_resultMap" resultMap="resultMap" parameterType="Integer">select * from t_user where t_id = #{id}</select></mapper>
    

    UserTest.java (测试类)

    public class UserTest {@org.junit.Test //单元测试public void selectUser_resultType_resultMap_Test() throws IOException {//1.读取mybatis框架的配置文件String resource = "com/myh/映射文件的元素/mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);//2.根据配置文件“构建会话工厂 : SqlSessionFactory ”SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//3.通过SqlSessionFactory(会话工厂)创建SqlSession("会话"对象)SqlSession sqlSession = sqlSessionFactory.openSession();User user1 = (User)sqlSession.selectOne("UserMapper.selectUser_resultType", 2);/**此处输出的内容为 : null ,因为字段名和属性名 不一样,数据无法映射成功,最后输出的内容为 : null*/System.out.println("从数据库中查询到的数据为(通过resultType获得): "+user1);/**此处输出的内容为 : "查询到的数据",即使“属性名” 和 “字段名”没有保持一致,但通过resultMap元素的配置,查询到的数据依然能映射到POJO类中。*/User user2 = (User)sqlSession.selectOne("UserMapper.selectUser_resultMap", 2);System.out.println("从数据库中查询到的数据为(通过resultMap获得): "+user2);//4.关闭SqlSessionsqlSession.close();}
    }
    

    控制台输出结果为
    在这里插入图片描述

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

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

相关文章

openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划

文章目录 openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划 openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划 完成资源负载管理功能配置前&#xff0c;需要先根据业务模型完成租户资源的规划。业…

绍兴市新昌县人大一行莅临迪捷软件走访考察

2024年2月29日下午&#xff0c;绍兴市新昌县人大常委会副主任王敏慧一行莅临迪捷软件走访考察&#xff0c;绍兴市委科创委副主任、科创走廊建设领导小组副组长、市人大一级巡视员王继岗&#xff0c;绍兴市科技局副局长、科创走廊建设办公室常务副主任梁枫陪同。 王主任一行听取…

九州金榜|导致孩子厌学因素有哪些?家庭教育中要怎样解决?

现在如今孩子出现厌学的情况越来越严重&#xff0c;这也难坏了很多家长&#xff0c;众所周知&#xff0c;当下社会竞争越来越激烈&#xff0c;孩子的压力也越来越大&#xff0c;这也是导致孩子厌学的主要因素。其实家庭因素也是引起孩子厌学情绪产生的重要原因&#xff0c;在家…

数据结构——二叉树的基本概念及顺序存储(堆)

目录 一.前言 二.树概念及结构 2.1 树的概念 2.2 树的相关概念 2.3 树的表现 2.4 树在实际中的应用&#xff08;表示文件系统的目录树结构&#xff09; 三.二叉树的概念及结构 3.1 概念 3.2 特殊的二叉树 3.3 二叉树的性质 3.4 二叉树的存储结构 3.4.1 顺序存储 3…

YOLOv9有效提点|加入SE、CBAM、ECA、SimAM等几十种注意力机制(一)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文将以SE注意力机制为例&#xff0c;演示如何在YOLOv9种添加注意力机制&#xff01; 《Squeeze-and-Excitation Networks》 SENet提出…

向上生长笔记

第一章 成为一个很厉害的人(持续输入&#xff0c;反复练习) 为什么要学习及如何学习 1、自毁趋势(熵增)&#xff0c;故需要能量输入(负熵流) //引申&#xff1a;水往低处流是趋势&#xff0c;学习是逆趋势。 2、持续输入能量&#xff08;物质和信息&#xff09;&#xff0c;…

力扣2月最后三天的每日一题

力扣2月最后三天的每日一题 前言2867.统计树中的合法路径数目思路确定1e5中的质数统计每个点的连接情况开始对质数点进行处理完整代码 2673.使二叉树所有路径值相等的最小代价思路完整代码 2581.统计可能的树根数目思路建立连通关系将猜测数组变为哈希表&#xff0c;方便查询利…

七通道NPN 达林顿管GC2003,专为符合标准 TTL 而制造,最高工作电压 50V,耐压 80V

GC2003 内部集成了 7 个 NPN 达林顿晶体管&#xff0c;连接的阵列&#xff0c;非常适合逻辑接口电平数字电路&#xff08;例 如 TTL&#xff0c;CMOS 或PMOS 上/NMOS&#xff09;和较高的电流/电压&#xff0c;如电灯电磁阀&#xff0c;继电器&#xff0c;打印机或其他类似的负…

读《代码整洁之道》有感

最近读了一本书&#xff0c;名字大家都看到了&#xff1a;《代码整洁之道》&#xff0c;之前一直只是听说过这本书的大名&#xff0c;却一直没有进行拜读&#xff0c;最近想起来了就想着看一看&#xff0c;不看不要紧&#xff0c;看了之后就像吃了炫迈&#xff0c;根本停不下来…

MATLAB环境下脑电信号EEG的谱分析

脑电信号一直伴随着人类的生命&#xff0c;脑电波是脑神经细胞发生新陈代谢、离子交换时细胞群兴奋突触电位总和&#xff0c;脑电信号的节律性则和丘脑相关&#xff0c;含有丰富的大脑活动信息。通常我们所接触的脑电图都是头皮脑电图&#xff0c;在有些特殊场合还需要皮下部位…

10.广域网技术

1. PPP实验点这里&#xff08;拓扑代码&#xff09; 2. PPPoE配置实验点这里&#xff08;拓扑代码&#xff09; 目录 一、广域网二、PPP协议三、PPP链路建立过程1-LCP&#xff08;链路协商&#xff09;四、PPP链路建立过程2-PAP/CHAP&#xff08;认证协商&#xff0c;可选&…

python语言1

一、pytho中的注释 1.1注释的理解 程序员在代码中对代码功能解释说明的标注性文字可以提高代码的可读性注释的内容将被python解释器忽略&#xff0c;不被计算机执行 1.2注释的分类 注释分为&#xff1a;单行注释、多行注释、中文声明注释 &#xff08;1&#xff09;单行注…

LeetCode240题:搜索二维矩阵II(python3)

代码思路&#xff1a; “根节点” 对应的是矩阵的 “左下角” 和 “右上角” 元素&#xff0c;以 matrix 中的左下角元素为标志数 flag &#xff0c;则有: 若 flag > target &#xff0c;则 target 一定在 flag 所在行的上方 &#xff0c;即 flag 所在行可被消去&#xff0c…

kotlin安卓开发教程视频,2024年Android开发陷入饱和

Android基础 1、什么是ANR 如何避免它&#xff1f; 如果耗时操作需要让用户等待&#xff0c;那么可以在界面上显示进度条。 2、View的绘制流程&#xff1b;自定义View如何考虑机型适配&#xff1b;自定义View的事件 3、分发机制&#xff1b;View和ViewGroup分别有哪些事件分…

【Leetcode每日一刷】贪心算法|122.买卖股票的最佳时机 II、55. 跳跃游戏

一、122.买卖股票的最佳时机 II 力扣题目链接 &#x1f984;解题思路&#xff1a; 首先需要明确的几个点&#xff1a; 当前只能有最大一支股票每一天操作只能3选1&#xff1a;买or卖or休息 此外&#xff0c;对于贪心&#xff0c;总有像下面图示的一种直觉&#xff1a;如果…

力扣SQL50 产品销售分析 I 查询

Problem: 1068. 产品销售分析 I 思路 left join on&#xff1a;左连接 Code select p.product_name, s.year, s.price from Sales s left join Product p on s.product_id p.product_id

靠谱的车【华为OD机试-JAVAPythonC++JS】

题目描述 程序员小明打了一辆出租车去上班。出于职业敏感&#xff0c;他注意到这辆出租车的计费表有点问题&#xff0c;总是偏大。 出租车司机解释说他不喜欢数字4&#xff0c;所以改装了计费表&#xff0c;任何数字位置遇到数字4就直接跳过&#xff0c;其余功能都正常。 比如&…

Scaffold 脚手架

Scaffold 脚手架 Scaffold 脚手架组件是一个核心组件&#xff0c;它为开发者提供了一个标准的、可定制的应用界面框架。androidx.compose.material3.Scaffold 包含了应用界面的基础元素&#xff0c;如状态栏、导航栏、顶部应用栏&#xff08;TopAppBar&#xff09;等。通过 Sc…

Windows的Docker-Desktop安装与问题总结

目录 Docker-Desktop安装步骤 环境配置 Docker-Desktop安装问题总结 问题1&#xff1a;docker-desktop setting界面一直加载转圈 问题2&#xff1a;docker镜像的存储位置变更&#xff08;防止C盘空间不足&#xff09; 参考文献&#xff1a; Docker-Desktop安装步骤 环境…

又挖到宝了!国人团队研发的AI视频工具PixVerse,这么好用居然还完全免费!(强烈推荐)

昨天发了一款国产免费的 AI 绘画工具 Dreamina 的介绍&#xff1a; 居然才发现&#xff01;字节跳动旗下国产AI绘画工具Dreamina&#xff0c;这么好用居然还免费&#xff01;&#xff08;强烈推荐&#xff09; 发现大家对国产 AI 工具还挺感兴趣的。今天继续帮大家挖国产的 A…