mybatis配置文件详解

您所在的位置:网站首页 mysql的驱动文件在哪里 mybatis配置文件详解

mybatis配置文件详解

2024-06-28 05:27:21| 来源: 网络整理| 查看: 265

目录

配置文件列表

1.properties(属性)

1.1 properties的配置

1.2 properties设置默认值

2、settings(设置)

settings配置参数

3、typeAliases(类型别名)

4、typeHandlers(类型处理器)

4.1 创建typeHandlers类型处理器

4.2 使用typeHandlers类型处理器

4.2.1 使用方式:全局配置

4.3 默认类型处理器

5、objectFactory(对象工厂)

6、plugins(插件)

7、environments(环境配置)

8、mappers(映射器)

使用相对路径进行配置

使用绝对路径进行配置

使用接口信息进行配置

使用接口所在包进行配置

配置文件列表 配置名称配置含义配置简介configuration包裹所有配置标签整个配置文件的顶级标签。properties属性该标签可以引入外部配置的属性,也可以自己配置。该配置标签所在的同一个配置文件中的其他配置均可引用此配置中的属性。settings全局配置参数用来配置一些改变运行时行为的信息。例如是否使用缓存机制,是否使用延迟加载,是否使用错误处理机制等。并且可以设置最大并发请求数量、最大并发事务数量,以及是否启用命名空间等。typeAliases类型别名用来设置一些别名来替代Java的长类型声明(如: java.lang.int变为int),减少配置编码的冗余。typeHandlers类型处理器将SQL中返回的数据库类型转换为相应的Java类型的处理器配置。objectFactory对象工厂实例化目标类的工厂类配置。plugins插件可以通过插件修改MyBatis的核心行为,例如对语句执行的某一点进行拦截调用。environments环境集合属性对象数据库环境信息的集合。在一个配置文件中,可以有多种数据库环境集合,这样可以使MyBatis将SQL同时映射至多个数据库。environment环境子属性对象数据库环境配置的详细配置。transactionManager事务管理指定MyBatis的事务管理器。dataSource数据源使用其中的type指定数据源的连接类型,在标签对中可以使用property属性指定数据库连接池的其他信息。mappers映射器配置SQL映射文件的位置,告知MyBatis去哪里加载SQL映射配置。 1.properties(属性) 1.1 properties的配置

在mybatis-config.xml配置文件中,properties标签中的数据可以供整个配置文件中的其他配置使用。properties标签可以可以引入一个动态变换的外部配置,如一个传统的Java配置文件,或者是一个properties参数配置文件。当然,在properties标签内部也可以放置property标签,来配置子元素信息。对于配置文件中的其他配置,可以通过property子标签的name属性来取得相应的value值。

一个properties标签配置如下(引入一个database.properties文件):

 database.properties文件内容

mysqldriver=com.mysql.cj.jdbc.Driver mysqlurl=jdbc:mysql://192.168.152.184:3306/jdbcstudb?allowMultiQueries=true mysqluser=root mysqlpwd=123456

TIP: database.properties配置文件中的 mysqluser,如果写成username,可能会与系统环境中的username变量冲突,所以到时候真正连接数据库的时候,用户名就被替换成系统中的用户名(有得可能是administrator),那肯定是连接不成功的。 

database.properties配置文件中配置了数据库的详细连接信息,properties标签这样引入它避免了数据库信息的“硬编码”。当需要连接其他数据库时,只需要更改要连接的数据库的配置文件的路径即可。

当然properties标签也可以包含property子标签,该子标签中的值也可以被配置文件中的其他配置使用,属于一种全局参数。可以看到,这里虽然引入了database.properties文件,但是其中的 mysqluser 和 mysqlpwd 还可以重新在property子标签中配置,这个时候取的值就是property子标签中的value值。这样配置是因为有时候有些模块的数据库连接的用户可能需要以不同的角色登录,这样可以在property子标签中动态分配数据库连接的用户mysqluser 和密码 mysqlpwd。

在properties标签中引入的配置文件信息以及property子标签中的配置信息,在其他标签中可以使用“${}”拼接符的方式来获取,在“${}”中填写引入的配置文件中的参数的name或者property子标签的name,样例配置中的数据源信息配置其实就是获取properties标签中的配置信息:

1.2 properties设置默认值

在MyBatis 3.4.2之后,还可以在“${}”拼接符中设置一个默认值,格式如下:

${属性:默认值}

即在所需引入的属性名的后面添加“:”引号,然后紧跟着填写属性不存在或为空时的默认值。

当然,首先要在properties标签中设置一个启用拼接符默认值的配置,该配置如下:

其他属性引入properties标签中的参数时,可以设置一个默认值

TIP:

由于在日常开发中数据库可能会发生变动,所以应避免将数据库配置信息硬编码。当然,过于集中的配置也不利于维护,所以这里单独为数据库配置一个database.properties文件,当需要更改数据库信息时,只需要更改database.properties文件即可。

2、settings(设置)

settings配置也是MyBatis全局配置文件中比较重要的配置,它影响MyBatiis框架在运行时的一些行为。settings配置缓存、延迟加载、结果集控制、执行器、分页设置、命名规则等一系列控制性参数,与MyBatis的运行性能息息相关。所有的setting配置都被包裹在settings标签对中。

settings配置参数 属性名简介有效值默认值cacheEnabled全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。true | falsetruelazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType属性来覆盖该项的开关状态。true | falsefalseaggressiveLazyLoading当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载(参考 lazyLoadTriggerMethods)。true | falsefalsemultipleResultSetsEnabled是否允许单一语句返回多结果集(需要驱动支持)。true | falsetrueuseColumnLabel设置是否使用列标签代替列名。true | falsetrueuseGeneratedKeys允许 JDBC 支持自动生成主键,需要驱动支持。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能支持但仍可正常工作(比如 Derby)。true | falsefalseautoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。NONE, PARTIAL, FULLPARTIALautoMappingUnknownColumnBehavior指定发现自动映射目标未知列(或者未知属性类型)的行为。 NONE: 不做任何反应; WARNING: 输出提醒日志; FAILING: 映射失败 (抛出 SqlSessionException);NONE, WARNING, FAILING   NONEdefaultExecutorType配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。SIMPLE REUSE BATCHSIMPLEdefaultStatementTimeout设置超时时间,它决定驱动等待数据库响应的秒数。任意正整数无defaultFetchSize为了防止从数据库查询出来的结果过多,而导致内存溢出,可以通过设置 fetchSize 参数来控制结果集的数量。任意正整数无safeRowBoundsEnabled允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。true | falsefalsesafeResultHandlerEnabled允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为 false。true | falsetruemapUnderscoreToCamelCase是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。true | falsefalselocalCacheScopeMyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。SESSION | STATEMENTSESSIONjdbcTypeForNull当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。JdbcType 常量,常用值:NULL, VARCHAR 或 OTHER。OTHERlazyLoadTriggerMethods指定哪个对象的方法触发一次延迟加载。用逗号分隔的方法列表。

equals,clone,

hashCode,toString

defaultScriptingLanguage指定动态 SQL 生成的默认语言。一个类型别名或完全限定类名。

org.apache.

ibatis.scripting.

xmltags.

XMLLanguageDriver

defaultEnumTypeHandler指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5)一个类型别名或完全限定类名。

org.apache.

ibatis.type.

EnumTypeHandler

callSettersOnNulls    指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值初始化的时候比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。true | falsefalsereturnInstanceForEmptyRow当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (如集合或关联)。(新增于 3.4.2)true | falsefalselogPrefix指定 MyBatis 增加到日志名称的前缀。任何字符串无logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING无proxyFactory代理工厂,指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。CGLIB | JAVASSISTJAVASSISTvfsImpl指定 VFS 的实现自定义 VFS 的实现的类全限定名,以逗号分隔。无useActualParamName允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1)true | falsetrueconfigurationFactory    指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3)类型别名或者全类名无

配置完整的settings案例

setting配置常用来实现缓存、延迟加载和分页设置。

3、typeAliases(类型别名)

一般会将JavaBean类型的封装类放置在一个包下面一个一个配置别名很繁琐,所以MyBatis提供了批量定义别名的方法,指定包名即可,程序会为该包下的所有包装类加上别名。定义别名的规则就是对应包装类的类名首字母变为小写。配置如下:

4、typeHandlers(类型处理器)

在MyBatis的SQL映射配置文件中,为SQL配置的输入参数最终要从Java类型转换成数据库能识别的类型,而从SQL的查询结果集中获取的数据,也要从数据库的数据类型转换为对应的Java类型。在MyBatis中,使用类型处理器(TypeHandler)将从数据库获取的值以合适的方式转换为Java类型,或者将Java类型的参数转换为数据库对应的类型。在MyBatis中有许多自带的类型处理器,但有时候也会满足不了开发的需求,这时候就需要配置自己的类型处理器了,typeHandlers标签就是用来声明自己的类型处理器的。

4.1 创建typeHandlers类型处理器

使用typeHandlers标签配置一个自己的类型处理器,一般需要三个步骤:编写类型处理器类,在MyBatis全局配置文件中配置该类型处理器,在SQL映射配置文件中使用。

下面编写一个将JDBC的TIMESTAMP类型与Java的String类型相互转换的类型转换器配置示例。首先编写类型处理器类,一般要实现 org.apache.ibatis.type.TypeHandler 接口,接口的泛型指定要转换的Java参数类型(若不指定则默认为Object类)。实现TypeHandler接口主要改写一下4个方法:

public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException; public String getResult(ResultSet rs, String columnName) throws SQLException; public String getResult(ResultSet rs, int columnIndex) throws SQLException; public String getResult(CallableStatement cs, int columnIndex) throws SQLException;

其中,setParameter方法是在为SQL配置传入参数时(新增、删除、修改以及条件查询)执行的操作,可以在将参数传入数据库之前在该方法中对数据类型做处理。另外三个 getResult 方法则在数据库返回结果时,将结果信息转换为相应的Java类型。它们之间的区别是,前两个 getResult 方法提供给普通的Select方法使用(一个根据字段名,一个根据字段下标来获取数据),最后一个 getResult 方法供存储过程使用(根据字段下标获取数据)。

【示例】编写一个将JDBC的TIMESTAMP类型与Java的String类型相互转换的类型转换器。

创建名称为DateStrTypeHandler的类型转换器,并实现TypeHandler接口。  

package com.pjb.mybatis.handler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; import java.sql.*; import java.text.SimpleDateFormat; /** * 字符串日期类型转换器 * @author pan_junbiao **/ public class DateStrTypeHandler implements TypeHandler { //设置日期转换格式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { Timestamp timestamp = Timestamp.valueOf(parameter); ps.setTimestamp(i,timestamp); } @Override public String getResult(ResultSet rs, String columnName) throws SQLException { Timestamp sqlTimestamp = rs.getTimestamp(columnName); return sqlTimestamp != null ? sdf.format(sqlTimestamp) : null; } @Override public String getResult(ResultSet rs, int columnIndex) throws SQLException { Timestamp sqlTimestamp = rs.getTimestamp(columnIndex); return sqlTimestamp != null ? sdf.format(sqlTimestamp) : null; } @Override public String getResult(CallableStatement cs, int columnIndex) throws SQLException { Timestamp sqlTimestamp = cs.getTimestamp(columnIndex); return sqlTimestamp != null ? sdf.format(sqlTimestamp) : null; } } 4.2 使用typeHandlers类型处理器 4.2.1 使用方式:全局配置

在MyBatis配置文件(SqlMapConfig.xml)中,配置类型转换器信息。

4.3 默认类型处理器

MyBatis已经提供了一些默认的类型处理器,这些默认的类型处理器都继承BaseTypeHandler类。

MyBatis提供默认的类型处理器:

类型处理器Java 类型JDBC 类型BooleanTypeHandlerjava.lang.Boolean, boolean数据库兼容的 BOOLEANByteTypeHandlerjava.lang.Byte, byte数据库兼容的 NUMERIC 或 BYTEShortTypeHandlerjava.lang.Short, short数据库兼容的 NUMERIC 或 SMALLINTIntegerTypeHandlerjava.lang.Integer, int数据库兼容的 NUMERIC 或 INTEGERLongTypeHandlerjava.lang.Long, long数据库兼容的 NUMERIC 或 BIGINTFloatTypeHandlerjava.lang.Float, float数据库兼容的 NUMERIC 或 FLOATDoubleTypeHandlerjava.lang.Double, double数据库兼容的 NUMERIC 或 DOUBLEBigDecimalTypeHandlerjava.math.BigDecimal数据库兼容的 NUMERIC 或 DECIMALStringTypeHandlerjava.lang.StringCHAR, VARCHARClobReaderTypeHandlerjava.io.Reader-ClobTypeHandlerjava.lang.StringCLOB, LONGVARCHARNStringTypeHandlerjava.lang.StringNVARCHAR, NCHARNClobTypeHandlerjava.lang.StringNCLOBBlobInputStreamTypeHandlerjava.io.InputStream-ByteArrayTypeHandlerbyte[]数据库兼容的字节流类型BlobTypeHandlerbyte[]BLOB, LONGVARBINARYDateTypeHandlerjava.util.DateTIMESTAMPDateOnlyTypeHandlerjava.util.DateDATETimeOnlyTypeHandlerjava.util.DateTIMESqlTimestampTypeHandlerjava.sql.TimestampTIMESTAMPSqlDateTypeHandlerjava.sql.DateDATESqlTimeTypeHandlerjava.sql.TimeTIMEObjectTypeHandlerAnyOTHER 或未指定类型EnumTypeHandlerEnumeration TypeVARCHAR 或任何兼容的字符串类型,用以存储枚举的名称(而不是索引值)EnumOrdinalTypeHandlerEnumeration Type任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的序数值(而不是名称)。SqlxmlTypeHandlerjava.lang.StringSQLXMLInstantTypeHandlerjava.time.InstantTIMESTAMPLocalDateTimeTypeHandlerjava.time.LocalDateTimeTIMESTAMPLocalDateTypeHandlerjava.time.LocalDateDATELocalTimeTypeHandlerjava.time.LocalTimeTIMEOffsetDateTimeTypeHandlerjava.time.OffsetDateTimeTIMESTAMPOffsetTimeTypeHandlerjava.time.OffsetTimeTIMEZonedDateTimeTypeHandlerjava.time.ZonedDateTimeTIMESTAMPYearTypeHandlerjava.time.YearINTEGERMonthTypeHandlerjava.time.MonthINTEGERYearMonthTypeHandlerjava.time.YearMonthVARCHAR 或 LONGVARCHARJapaneseDateTypeHandlerjava.time.chrono.JapaneseDateDATE 5、objectFactory(对象工厂)

SQL映射配置文件中的SQL语句所得到的查询结果,会动态映射到resultType或者其他处理结果集的参数配置对应的Java类型,其中就有JavaBean等封装类。而objectFactory(对象工厂)就是用来创建实体对象的类。

在MyBatis中,默认的objectFactory要做的就是实例化查询结果对应的目标类,有两种方式可以将查询结果的值映射到对应的目标类,一种是通过目标类的默认构造方法,另外一种就是通过目标类的有参构造方法。

有时候在New一个新对象时(构造方法或者有参构造方法),在得到对象之前需要处理一些逻辑,或者在执行该类的有参构造方法时,在传入参数之前,要对参数进行一些处理,这是就可以创建自己的objectFactory来加载该类型的对象。

如果想改写默认的对象工厂,可以继承DefaultObjectFactory来创建自己的对象工厂,从而改写相关的4个方法,如:

package com.pjb.mybatis.objectFactory; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import java.util.List; import java.util.Properties; /** * 自定义objectFactory(对象工厂) * @author pan_junbiao **/ public class MyObjectFactory extends DefaultObjectFactory { //处理默认构造方法 public Object create(Class type) { return super.create(type); } //处理有参构造方法 public Object create(Class type, List constructorArgTypes, List constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } //处理参数 public void setProperties(Properties properties) { super.setProperties(properties); } //判断集合类型参数 public boolean isCollection(Class type) { return Collection.class.isAssignableFrom(type); } }

编写好自己的对象工厂之后,在MyBatis的全局配置文件mybatis-config.xml中添加以下配置,这样才能使对象工厂生效:

其中的property参数,会在加载全局配置文件mybatis-config.xml时通过setProperties方法被初始化到MyObjectFactory中,作为该类的全局参数使用。\

6、plugins(插件)

在某种情况下,需要在执行程序的过程中对某一点进行拦截,并在拦截后做出一系列处理,此时就需要使用一种“拦截器”。在MyBatis中,对某种方法进行拦截调用的机制,被称为 plugin 插件。使用 plugin 可以很好地对方法地调用进行监控,而且还可以修改或重写方法的行为逻辑。在 MyBatis 中允许使用 plugin 来拦截的方法如下:

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler (getParameterObject, setParameters) ResultSetHandler (handleResultSets, handleOutputParameters) StatementHandler (prepare, parameterize, batch, update, query)

其中,Executor是MyBatis对外提供的一个操作接口类,其中包含了query 查询、update 修改、commit 提交、rollback 回滚等核心方法。ParameterHandler、ResultSetHandler 及 StatementHandler 分别是处理参数、结果集、预编译状态的接口,里面的一些方法也可以使用plugin进行拦截。值得一提的是,plugin可以操作MyBatis的框架核心方法。在修改plugin时可能会影响框架的稳定性,所以在编写plugin时要十分谨慎。

实现一个plugin很简单,只需要继承Interceptor接口,并且指定需要拦截的方法的签名信息即可。

如下是一个基础拦截器的实现:

package com.pjb.mybatis.plugins; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import java.util.Properties; import java.util.concurrent.Executor; /** * Query拦截器 * @author pan_junbiao **/ @Intercepts({ @Signature( type = Executor.class, method="query", args={MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class} ) }) public class QueryPlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { } }

这里,在插件的类头部添加了“@Intercepts”拦截器注解,此注解声明此类是一个插件类。其中可以声明多个 @Signature 签名信息注解,type为拦截的方法所属的接口类型,method为拦截的方法名称,args是需要的参数信息。其中intercept方法是一个对目标方法进行拦截的抽象方法,而plugin方法的作用是将拦截器插入目标对象。setProperties方法的作用是将全局配置文件中的参数注入插件类中。这里的示例插件中对Executor的query方法进行了拦截调用。

编写了插件类后,还要找在MyBatis 全局配置文件中配置该插件即可,这样插件就会起到拦截作用,示例代码如下:

此时就可以拦截Executor的query方法了,也即是默认执行的查询方法,可以在重写的插件类的intercept方法中添加拦截逻辑。

插件使用的场景有:日志记录、权限控制、缓存控制等。

使用plugin拦截和覆盖MyBatis的核心方法时,一定要小心谨慎,否则可能会影响MyBatis的核心功能。

7、environments(环境配置)

在MyBatis全局配置文件中,environments是放置有关数据库连接数据的配置标签,所有与外部数据库进行交互的数据都配置在该标签中,在environments标签中可以配置多个数据库连接环境,以便SQL语句可以适用于多个数据库环境。

在environments中可以配置一个个单独的environment,它们代表多个数据库环境的配置信息。每个environment都包含事务管理器(transactionManager)和数据源(dataSource)信息。如下是一个完整的environments配置:  

8、mappers(映射器)

MyBatis是基于SQL映射配置的框架,SQL语句都写在Mapper配置文件中,那么当构建SqlSession类之后,是需要读取Mapper 配置文件中的SQL配置。而mappers标签就是用来配置需要加载的SQL映射配置文件路径的。

mappers标签下有许多mapper子标签,每一个mapper子标签中配置的都是一个独立的Mapper映射配置文件的路径。有以下几种配置方式:

使用相对路径进行配置             使用绝对路径进行配置             使用接口信息进行配置             使用接口所在包进行配置    

配置了mappers信息后,MyBatis就知道去哪里加载Mapper映射文件。在MyBatis中,mappers配置是MyBatis全局配置文件中比较重要的配置



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭