1. Mybatis中如何实现批量数据的插入,请写出配置文件的配置信息以及java代码的源
MyBatis提供用于插入数据的注解有两个:@insert,@InsertProvider,类似还有:@[email protected],和@SelectProvider,作用:用来在实体类的Mapper类里注解保存方法的SQL语句区别:@Insert是直接配置SQL语句,而@InsertProvider则是通过SQL工厂类及对应的方法生产SQL语句,这种方法的好处在于,我们可以根据不同的需求生产出不同的SQL,适用性更好。使用:@Insert@Insert(“insert into blog(blogId,title,author) values(#blogId,#title,#author)”)public boolean saveBlog(Blog blog);@InsertProvider在mapper接口中的方法上使用@InsertProvider注解:参数解释:type为工厂类的类对象,method为对应的工厂类中的方法,方法中的@Param(“list”)是因为批量插入传入的是一个list,但是Mybatis会将其包装成一个map。其中map的key为“list”,value为传入的list。
2. mybatis各阶段的详解
比如我们在引入了jdbc的配置文件使用了properties标签,引入jdbc有什么好处?,可以在配置文件中统一管理 内容而不是在很多个文件改来改去,而且在核心配置文件中把数据库连接相关的写死,显然是硬编码的所以我们用配置文件代替 nice!!!
你可能注意到了上面的写法 用前缀jdbc. 可以很好地将他们与其他的变量区分开,(可以从名字很容易看出是jdbc相关的数据,不至于和同名变量搞混因为username这种可能 不止会出现在数据库的连接)
上面的代码中引入配置文件的部分为 可以从上面看到写法:
下面这段就是用来设置类的别名:
那么问题来了,为什么要有类的别名这种操作??
因为在映射文件中每次都要写全类名显然有点麻烦比如下面这样:
一个项目是会有很多个映射文件的为了方便,所以类别名就出现了。可以在核心配置文件写接口类和对应的别名
这样就可以在映射文件的命名空间里可以直接写User(对大小没有要求也可以是user; 其实可以比这更加简单,也是我们在实际开发中常用的写法 就是将整个包写成别名的形式,如果不写alias属性默认为类名(不区分大小写),这样就容易多了,我们只需一行代码,便可以在所有的映射文件命名空间 中直接写对应的类名
引入核心的配置文件
首先需要思考的这里是映射文件的引入,我们正常的一个项目的数据库是有很多个表组成的那么每一张表对应一个mapper接口,每个接口对应一个映射文件,那么就需要导入大量的映射文件,还容易漏掉–>
上面这种以包的形式的导入非常方便,不用每次新建一个接口就要导入它的映射文件,但是上面这种写法需要 注意 一些问题:
如果你在映射文件中编写查询语句的sql,但是粗心的你忘记了设置返回类型会在控制台抛异常且会看到这样的说明: It's likely that neither a Result Type nor a Result Map was specified.
下面只是指定返回类型的一种方式:resultType,还有 resultMap 它们的区别:
查询的标签必须指定resultType或resultMap
com.kobe.mybatis 获取参数的两种方式:${} 和 #{}
上面是使用了 #{}写法相当于原生jdbc的占位符,这个前面已经提到过了所以不多赘述, 需要注意的是#{}里面的变量名可以是任意的username规范显然很好,但是aaaa也没错因为只是用来占位的; 还有就是在使用${}时注意''单引号问题,因为${}是字符拼接的方式,所以需要注意!!
传输参数时有多个参数时
在测试代码里通过传入两个参数分别为 username和password 但是在上面代码的(映射文件里的部分代码)执行失败,(sql语句未能解析) 报错: Cause: org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]
可以从错误提示的信息不难发现我们的参数在映射文件里未能真正地接受到,可以用[arg1, arg0, param1, param2] 的方式获取,mybatis将参数放到map容器可以通过建arg0,agr1..的方式 获取参数(也可以是param1,param2..) 将上面的代码改动:
需要注意的是:使用${}时需要手动添加''才能正常访问,因为他的处理方式是字符串的拼接
做了改动之后结果很感人!! User{id=6, userName='旺财', age=20, password='cwlz'}
可以直接通过键访问相对应的值(通过自己的方式访问到数据,上面的形式是mybatis默认提供的map和mybatis默认的提取指的方式 arg0,arg2…) 当需要传多个参数时将他们放到一个map容器,然后将map传给对应的方法(模拟mybatis的做法,就可以在sql语句中直接通过键访问到值)代码如下:
映射文件中的部分代码 :
通过键直接获取值,注意:使用${}时不要忘了单引号!!!!
当参数以实体对象的形式传参时如何解决? 只需要通过#{}以属性名的方式访问!
所以代码的编写一定要规范,才能减少这种错误!!!
一定要和注解中的参数名一一对应!!!
如果查询的结果只有一个,也可以通过Map集合接收,字段名为键字段的值为值:{password=0000, id=3, userName=图区, age=20}
java.lang.Ingeger –> int ,Integer
int –> _int,_Integer
Map –> map
String –> string
注意:
所以在批量删除的案例:需要注意的是不能使用#{} 因为它是会自动添加'' 所以在批量删除的语句中我们要使用${}
若字段和属性名不一致 ,则可以通过resultMap设置自定义映射
在mybatis的核心配置文件用下面的代码将 数据库中命名的规范 (user_name) 转换为 java中的命名规范 (userName)
就是手动设置属性与字段的映射关系: 如果设置了手动的设置属性和字段的映射关系,注意主键使用 id 标签,普通字段使用 result标签,就算属性和字段名一一对应,只要 用了这种方式就 必须要写全 !!!
一对多的查询:
通过分步查询实现:
多条件的查询
if 根据标签中test的属性所对应的表达式决定标签中的内容是否拼接到sql语句中
上面的where后面的 1=1 是细节,因为当where后面的条件都为空时就成了 select * from t_user where 显然这种sql语句是有问题的,还有一种情况就是当userName为null时语句就成了 select * from t_user where and age=#{age} 这也是错的,所以在where后加一个恒成立的条件不仅不会影响查询结果,而且没有会在特定情况时sql语句是会报错的所以很有必要
where 当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and 或者or去掉 当where中没有内容时,此时where标签没有任何效果 就是不会生成关键字 注意:在写条件时不能在后面加and or 这个在下一条语句无效时mybatis不会帮你去掉!
相当于 if else
一个案例 –>就是当我们需要批量删除一些东西时(参数以数组的形式传入)
sql 片段: 在我们的查询语句不能在实际开发中也一直写 *;因为我们要按需查找,不必将不需要的也查询出来,我们可以将我们平常查询次数较多的字段 放在sql片段内,可以在需要查询时直接进行引用!
缓存,这个术语我们听过很多次,在web阶段时访问网页时有缓存机制! 现在sql的查询时也有缓存机制,有一级缓存,一级缓存是默认开启的,一级缓存的范围时sqlSession,将我们查询到的数据先进行缓存,若下次有相同的查询时不用重新 访问数据库,可以直接从缓存中取出!!!!
手动清空缓存 sqlSession.clearCache();
在mapper配置文件中添加cache标签可以设置一些属性:
逆向工程就是不难理解,我们之前都是由实体类到数据库,而逆向类就是通过数据库表生成实体类,
3. MyBatis解析
从命名上可以看出,这个是一个 Builder 模式的,用于创建 SqlSessionFactory 的类。SqlSessionFactoryBuilder 根据配置来构造 SqlSessionFactory。其中配置方式有两种: mybatis-config.xml 就是我们的配置文件: Java Config 相比较 XML 文件的方式而言,会有一些限制。比如修改了配置文件需要重新编译,注解方式没有 XML 配置项多等。所以,业界大多数情况下是选择 XML 文件的方式。但到底选择哪种方式,这个要取决与自己团队的需要。比如,项目的 SQL 语句不复杂,也不需要一些高级的 SQL 特性,那么 Java Config 则会更加简洁一点;反之,则可以选择 XML 文件的方式。 创建配置文件解析器XMLConfigBuilder 解析mybatis-config.xml里的配置为Configuration对象,Mybatis的全局配置对象。 XMLConfigBuilder#parseConfiguration解析mapper下的xml XMLMapperBuilder#bindMapperForNamespace,根据xml里的 namespace 反射出 mapper接口 的 class,如果有mapper接口,则把该mapper接口的class添加到Configuration的mapperRegistry里。 如果该接口已经注册,则抛出已经绑定的异常。 为该接口注册MapperProxyFactory,但这里只是注册其创建MapperProxy的工厂,并不是创建MapperProxy。 如果Mapper对应的xml资源未加载,触发xml的绑定操作,将xml中的sql语句与Mapper建立关系。 addMapper方法,只是为**Mapper创建对应对应的MapperProxyFactory。 根据Mapper接口与SqlSession创建MapperProxy对象。 根据接口类获取MapperProxyFactory。 调用MapperProxyFactory的newInstance创建MapperProxy对象。 SqlSessionFactory 顾名思义,是用于生产 SqlSession 的工厂。 通过如下的方式来获取 SqlSession 实例: SqlSession 包含了执行 SQL 的所有的方法。以下是示例: 当然,下面的方式可以做到类型安全: MapperProxy是MapperProxyFactory使用SqlSession创建出来的。所以MapperProxy中包含SqlSession。 可以看到MapperProxy调用invoke方法,进而调用MapperMethod的execute(),这些MapperMethod就是和你要执行的命令相关,比如执行select语句,则会通过SqlSession的select()方法,最终调用到Executor的query方法。Executor会再协调另外三个核心组件。 MapperProxy: MapperMethod: 插件的构建: 谈原理首先要知道StatementHandler,ParameterHandler,Result Handler都是代理,他们是Configuration创建,在创建过程中会调用interceptorChain.pluginAll()方法,为四大组件组装插件(再底层是通过Plugin.wrap(target,XX, new Plugin( interceptor))来来创建的)。 插件链是何时构建的: 在执行SqlSession的query或者update方法时,SqlSession会通过Configuration创建Executor代理,在创建过程中就调用interceptor的pluginAll方法组装插件。然后executor在调用doQuery()方法的时候,也会调用Configuration的newStatementHandler方法创建StatemenHandler(和上面描述的一样,这个handler就是个代理,也是通过interceptorChain的pluginAll方法构建插件) 插件如何执行: 以statementhandler的prepare方法的插件为例,正如前面所说,statementhandler是一个proxy,执行他的prepare方法,将调用invokeHandler的invoke方法,而invokeHandler就是Plugin.wrap(target, xxx, new Plugin(interceptor))中的第三个参数,所以很自然invokeHanlder的invoke的方法最终就会调用interceptor对象的intercept方法。 Mybatis的插件配置在configuration内部,初始化时,会读取这些插件,保存于Configuration对象的InterceptorChain中。 org.apache.ibatis.plugin.InterceptorChain.java源码。 上面的for循环代表了只要是插件,都会以责任链的方式逐一执行,所谓插件,其实就类似于拦截器。 插件的编写 插件必须实现org.apache.ibatis.plugin.Interceptor接口。 -intercept()方法:执行拦截内容的地方,拦截目标对象的目标方法的执行 -plugin()方法:决定是否触发intercept()方法。 作用:包装目标对象,包装就是为目标对象创建一个代理对象 -setProperties()方法:给自定义的拦截器传递xml配置的属性参数。将插件注册时的property属性设置进来 下面自定义一个拦截器: 为什么要写Annotation注解?注解都是什么含义? Mybatis规定插件必须编写Annotation注解,是必须,而不是可选。@Intercepts注解:装载一个@Signature列表,一个@Signature其实就是一个需要拦截的方法封装。那么,一个拦截器要拦截多个方法,自然就是一个@Signature列表。 type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class } 解释:要拦截Executor接口内的query()方法,参数类型为args列表。 Plugin.wrap(target, this)是干什么的? 使用JDK的动态代理,给target对象创建一个delegate代理对象,以此来实现方法拦截和增强功能,它会回调intercept()方法。 Mybatis可以拦截哪些接口对象? Mybatis只能拦截ParameterHandler、ResultSetHandler、StatementHandler、Executor共4个接口对象内的方法。 重新审视interceptorChain.pluginAll()方法:该方法在创建上述4个接口对象时调用,其含义为给这些接口对象注册拦截器功能,注意是注册,而不是执行拦截。 拦截器执行时机:plugin()方法注册拦截器后,那么,在执行上述4个接口对象内的具体方法时,就会自动触发拦截器的执行,也就是插件的执行。 Invocation 可以通过invocation来获取拦截的目标方法,以及执行目标方法。 分页插件原理 由于Mybatis采用的是逻辑分页,而非物理分页,那么,市场上就出现了可以实现物理分页的Mybatis的分页插件。 要实现物理分页,就需要对String sql进行拦截并增强,Mybatis通过BoundSql对象存储String sql,而BoundSql则由StatementHandler对象获取。 因此,就需要编写一个针对StatementHandler的query方法拦截器,然后获取到sql,对sql进行重写增强。
4. spring整合mybatis怎样配置注解
mybatis和spring的整合步骤:1)使用mybatis,必须有个全局配置文件configuration.xml,来配置mybatis的缓存,延迟加载等等一系列属性,该配置文件示例如下: Java代码 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-config.dtd"> <configuration> <settings> <!– 全局映射器启用缓存 –> <setting name="cacheEnabled" value="true" /> <!– 查询时,关闭关联对象即时加载以提高性能 –> <setting name="lazyLoadingEnabled" value="true" /> <!– 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 –> <setting name="aggressiveLazyLoading" value="false" /> <!– 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 –> <setting name="multipleResultSetsEnabled" value="true" /> <!– 允许使用列标签代替列名 –> <setting name="useColumnLabel" value="true" /> <!– 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 –> <setting name="useGeneratedKeys" value="true" /> <!– 给予被嵌套的resultMap以字段-属性的映射支持 –> <setting name="autoMappingBehavior" value="FULL" /> <!– 对于批量更新操作缓存SQL以提高性能 –> <setting name="defaultExecutorType" value="BATCH" /> <!– 数据库超过25000秒仍未响应则超时 –> <setting name="defaultStatementTimeout" value="25000" /> </settings> <!– 全局别名设置,在映射文件中只需写别名,而不必写出整个类路径 –> <typeAliases> <typeAlias alias="TestBean" type="com.wotao.taotao.persist.test.dataobject.TestBean" /> </typeAliases> <!– 非注解的sql映射文件配置,如果使用mybatis注解,该mapper无需配置,但是如果mybatis注解中包含@resultMap注解,则mapper必须配置,给resultMap注解使用 –> <mappers> <mapper resource="persist/test/orm/test.xml" /> </mappers> </configuration> 2)该文件放在资源文件的任意classpath目录下,假设这里就直接放在资源根目录,等会spring需要引用该文件。 查看ibatis-3-config.dtd发现除了settings和typeAliases还有其他众多元素,比如properties,objectFactory,environments等等,这些元素基本上都包含着一些环境配置,数据源定义,数据库事务等等,在单独使用mybatis的时候非常重要,比如通过以构造参数的形式去实例化一个sqlsessionFactory,就像这样: Java代码 SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader); SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, properties); SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, properties); 而typeHandlers则用来自定义映射规则,如可以自定义将Character映射为varchar,plugins元素则放了一些拦截器接口。2)在spring配置文件中指定c3p0数据源定义如下: Java代码 <!– c3p0 connection pool configuration –> <bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!– 数据库驱动 –> <property name="driverClass" value="${db.driver.class}" /> <!– 连接URL串 –> <property name="jdbcUrl" value="${db.url}" /> <!– 连接用户名 –> <property name="user" value="${db.username}" /> <!– 连接密码 –> <property name="password" value="${db.password}" /> <!– 初始化连接池时连接数量为5个 –> <property name="initialPoolSize" value="5" /> <!– 允许最小连接数量为5个 –> <property name="minPoolSize" value="5" /> <!– 允许最大连接数量为20个 –> <property name="maxPoolSize" value="20" /> <!– 允许连接池最大生成100个PreparedStatement对象 –> <property name="maxStatements" value="100" /> <!– 连接有效时间,连接超过3600秒未使用,则该连接丢弃 –> <property name="maxIdleTime" value="3600" /> <!– 连接用完时,一次产生的新连接步进值为2 –> <property name="acquireIncrement" value="2" /> <!– 获取连接失败后再尝试10次,再失败则返回DAOException异常 –> <property name="acquireRetryAttempts" value="10" /> <!– 获取下一次连接时最短间隔600毫秒,有助于提高性能 –> <property name="acquireRetryDelay" value="600" /> <!– 检查连接的有效性,此处小弟不是很懂什么意思 –> <property name="testConnectionOnCheckin" value="true" /> <!– 每个1200秒检查连接对象状态 –> <property name="idleConnectionTestPeriod" value="1200" /> <!– 获取新连接的超时时间为10000毫秒 –> <property name="checkoutTimeout" value="10000" /> </bean> 配置中的${}都是占位符,在指定数据库驱动打war时会自动替换,替换的值在父pom中配置。3)需要一个sessionFactory来生成session,sessionFactory配置如下: Java代码 <bean id="testSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:configuration.xml" /> <property name="dataSource" ref="testDataSource" /> </bean> 4)配置一个映射器接口来对应sqlSessionTemplate,该映射器接口定义了接口方法:Java代码 <!– data OR mapping interface –> <bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="testSqlSessionFactory" /> <property name="mapperInterface" value="com.wotao.taotao.persist.test.mapper.TestMapper" /> </bean> 5)至此,一个完整的myabtis整合spring的配置文件看起来应该如下所示: Java代码 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!– c3p0 connection pool configuration –> <bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${db.driver.class}" /> <property name="jdbcUrl" value="${db.url}" /> <property name="user" value="${db.username}" /> <property name="password" value="${db.password}" /> <property name="initialPoolSize" value="5" /> <property name="minPoolSize" value="5" /> <property name="maxPoolSize" value="20" /> <property name="maxStatements" value="100" /> <property name="maxIdleTime" value="3600" /> <property name="acquireIncrement" value="2" /> <property name="acquireRetryAttempts" value="10" /> <property name="acquireRetryDelay" value="600" /> <property name="testConnectionOnCheckin" value="true" /> <property name="idleConnectionTestPeriod" value="1200" /> <property name="checkoutTimeout" value="10000" /> </bean> <bean id="testSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:configuration.xml" /> <property name="dataSource" ref="testDataSource" /> </bean> <!– data OR mapping interface –> <bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="sqlSessionFactory" ref="testSqlSessionFactory" /> <property name="mapperInterface" value="com.wotao.taotao.persist.test.mapper.TestMapper" /> </bean> <!– add your own Mapper here –> <!– comment here, using annotation –> <!– <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> –> <!– <constructor-arg index="0" ref="sqlSessionFactory" /> –> <!– </bean> –> <!– base DAO class, for mole business, extend this class in DAO –> <!– <bean id="testBaseDAO" class="com.test..TestBaseDAO"> –> <!– <property name="sqlSessionTemplate" ref="sqlSessionTemplate" /> –> <!– </bean> –> <!– <bean id="testDAO" class="com.test..impl.TestDAOImpl" /> –> <!– you can DI Bean if you don't like use annotation –> </beans>