首先讨论一下基本的概念~:
(1)MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
(2)MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
(3)MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录.
(4)是半自动化持久层框架,就是操作一个单表,也要自己写sql语句 Hibernate是全自动的sql就不容易做特殊优化
(5)jdbc编程—当我们使用jdbc持久化的时候,sql语句被硬编码到java代码中。这样耦合度太高。代码不易于维护。在实际项目开发中会经常添加sql或者修改sql,这样我们就只能到java代码中去修改。
分隔~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
使用:
需要导入jar包:
log4j-1.2.17.jar 日记
mybatis-3.4.1.jar mybatis的
mysql-connector-java-5.1.7-bin.jar mysql驱动
添加配置文件:
mybatis-config.xml 核心配置文件 名字暂时可以随便取
log4j.properties 日记配置文件
1写一个.xml文件 充当核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<!-- dataSource 数据源
POOLED 表示使用数据库连接池
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- 引入sql语句对应的配置文件 -->
<mappers>
<mapper resource="com/xxx/pojo/UserMapper.xml" />
</mappers>
</configuration>
2 log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3写数据库表单对应的javaBean对象 xxx (我用了User类)
4写xxxMapper.xml来映射sql语句 然后将此配置文件配置到核心配置文件中去 注意名字不要改其他的 是规范
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace 是名称空间 属性一般情况下。
一种定义规则:
一种是使用对流的javaBean的全类名
一种是使用Mapper接口的全类名
-->
<mapper namespace="com.xxx.pojo.User">
<!--
select 定义select查询语句
id 给你要定义的sql语句,设置一个唯一的id值。
resultType 查询完返回的类型
parameterType 设置参数的类型(例如在delete update insert语句中使用)
#{id} 这是一个占位符
-->
<select id="selectUserById" resultType="com.xxx .pojo.User"> //注意这里resultType对单个对象和集合都适用
select id,last_name lastName,sex from t_user where id = #{id}
</select>
</mapper>
5利用org.apache.ibatis.io.Resources读取核心配置文件
(1)Resources.getResourceAsStream("前面写的核心配置文件"); //返回一个输入流
(2)new SqlSessionFactoryBuilder().build(输入流); //通过SqlSessionFactoryBuilder 创建SqlSessionFactory实例 注意此实例在一个项目中只有一个实例!~~~~~~
(3)关闭输入流
(4)通过SqlSessionFactory调用openSession方法创建SqlSession对象 (相当于Connection对象)
(6)SqlSession调用selectOne执行select查询语句返回一个对象(名称空间值+sql映射配置文件select标签id值,参数)
selectList
insert 等更新需要自己commit
(5)关闭SqlSession
我们可以自己写DAO接口以及实现类 然偶胡在构造器或者set方法中将sqlSessionFactory赋值进去,即可以把上面5(4)的方法通过自己写的dao来调用~
**
插入之后返回主键值
**
方法(1)insert标签:useGeneratedKeys=“true” keyProperty="id"配置返回的值赋给对象里的id
方法(2)selectKey标签 用来定义sql语句 在其他语句之前或之后执行(此时看log会发现执行了两条语句~)
在insert标签内部写:
<selectKey order=“BEFORE”>SELECT LAST_INSERT_ID()</selectKey>
order属性设置selectKey语句执行的顺序 在这里要用after
keyProperty配置返回的值赋给对象里的id
**
Mapper接口方式实现增删改查
**
可以不用自己写实现类 只需要写接口就可以用
要求:(1)Mapper.java类名和Mapper.xml配置文件名一样
(2)放在同一个包下
1 <mapper namespace=“接口全类名”
2 标签id必须跟接口方法名相同 parameterType和resultType也必须完全一样
3 SqlSession调用getMapper方法 参数传入接口类名.class
Mybatis接口实现的原理:JDK动态代理
1通过mapperProxyFactory.newInstance(sqlSession)创建代理对象
底层就是Proxy.newProxyInstance返回的代理对象
会判断调用的sql是什么方法 例如如果是select 再判断是不是返回多个还是单个 还是map 还是油表 如果是单个 就执行sqlSession.selectOne
**
利用核心配置文件properties
**
resource写上自己写的jdbc文件 里面的内容会起作用 而不是在主配置文件里的properties起做用
**
mybatis的核心配置setting
**
<settings><setting name... value...></setting>
1 mapUnderscoreToCamelCase自动开启数据库列名的映射的驼峰标示(下划线变驼峰) 默认为false
**
mybatis的核心配置typeAliases别名
**
<typeAliases>
<typeAlias type="全类名" alias="别名" 定义一个别名 以后这个类在配置文件中就可以用别名标示了
<package name="包名"> 自动扫描指定包下的所有类 别名就是类名首字母小写
</typeAliases>
若果两个包下面有相同的类名 就可以使用@Alias("别名")来定义别名
**
类处理器typeHandlers
**
Mybatis和PreparedStatement中都会使用类型处理器将获取到的值以合适的方式转换成为java类型
类型处理器 Java 类型 JDBC 类型
BooleanTypeHandler java.lang.Boolean, boolean 数据库兼容的 BOOLEAN
ByteTypeHandler java.lang.Byte, byte 数据库兼容的 NUMERIC 或 BYTE
ShortTypeHandler java.lang.Short, short 数据库兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandler java.lang.Integer, int 数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandler java.lang.Long, long 数据库兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandler java.lang.Float, float 数据库兼容的 NUMERIC 或 FLOAT
DoubleTypeHandler java.lang.Double, double 数据库兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandler java.math.BigDecimal 数据库兼容的 NUMERIC 或 DECIMAL
StringTypeHandler java.lang.String CHAR, VARCHAR
ClobReaderTypeHandler java.io.Reader -
ClobTypeHandler java.lang.String CLOB, LONGVARCHAR
NStringTypeHandler java.lang.String NVARCHAR, NCHAR
NClobTypeHandler java.lang.String NCLOB
BlobInputStreamTypeHandler java.io.InputStream -
ByteArrayTypeHandler byte[] 数据库兼容的字节流类型
BlobTypeHandler byte[] BLOB, LONGVARBINARY
DateTypeHandler java.util.Date TIMESTAMP
DateOnlyTypeHandler java.util.Date DATE
TimeOnlyTypeHandler java.util.Date TIME
SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP
SqlDateTypeHandler java.sql.Date DATE
SqlTimeTypeHandler java.sql.Time TIME
ObjectTypeHandler Any OTHER 或未指定类型
EnumTypeHandler Enumeration Type VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引)
EnumOrdinalTypeHandler Enumeration Type 任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)。
**
mybatis核心配置之environments环境
**
1可以配置多个环境 映射多个数据库 在environments里面配置多个environment 更改id 就好
2transactionManager 有两个参数 jdbc(有事务) MANAGED这个配置没做什么
如果用的spring+myabits这个2transactionManager就没意义 因为会被spring的配置覆盖掉
**我们也可以自定义事务管理器:
(1)实现TransactionFactory
(2)实现Transaction 并且在 TransactionFactory方法中返回
然后把自定义的事务管理器的全类名放在transactionManager的type属性当中 就可以实现自己的事务管理器 我们可以在自己的类中写自己的方法~
**
mybatis核心配置之databaseIdProvider
**
让mybatis支持多种数据库
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver" />
<property name="MySQL" value="mysql" />
<property name="DB2" value="db2" />
<property name="Oracle" value="oracle" />
</databaseIdProvider>
在Mapper.xml中的sql语句标签可以配置databaseId属性 在我们使用不同数据库的时候 就会动态的找寻相对应的语句执行~
**
mybatis核心配置之映射器mappers
**
作用:引入sql语句对应的mapper配置文件
1利用类路径下的资源路径:<mapper resource="">这里写的是xml文件
2使用mapper接口的方式 <mapper class="接口全类名"> 这里写的是全类名 可以通过指定类扫描mapper配置文件
3使用包名 <package name="包名"> 搜索所有包名下的配置文件
**
使用注解的方式映射sql语句
**
此时就不需要使用Mapper.xml来映射sql语句了
在接口的方法上写:
(1)@Select (value=“”) @Update (value=“”) @Delete (value=“”) @Insert (value=“”)
insert语句可以再写一个注解: @SelectKey(before=false,statement=“select last_insert_id()”,keyProperty=“id”,resultType=Integer。class)来将生成的id返回
(2)mappers 改成<mapper class="接口全类名"> 这里写的是全类名 可以通过指定类扫描mapper配置文件
**
Mybatis sql映射文件参数传递
**
(1)一个普通数据类型 写变量名 #{变量名}
(2)多个普通数据类型 用#{param1} #{param2} #{param3}
或者用注解的方式@param("")然后就可以用#{前面写的名字}来使用了
(3)传递的是一个对象(包括map对象)用#{属性名或者key名}
(4)传递多个pojo对象 使用#{param1.属性名} #{param2.属性名}
**
{} 和 ${}的区别
**
#{}是占位符?
xml中配置的是#{}会解析成 ?
${}是原样输出参数的值 并且需要做字符串拼接的操作
xml中的配置: '${xxx}'
若果需要模糊查询 我们一般使用:concat('%',#{参数},'%')
**
自定义结果集
**
用来解决查询的pojo对象中包含pojo对象或者pojo对象集合的情况~ 此时需要使用resultMap自定义返回的结果
resultMap上的属性
type :返回的对象全类名
id的值是resultMap的值
里面的标签:
id 专门用来映射id主键列
result 映射非主键列 可以使用集联映射来给pojo中的pojo赋值 column是查询出来的字段名 property是bean对象的属性
association标签专门映射pojo中的一个bean对象: property是pojo对象中bean对象的属性名 javaType是pojo对象中bean对象的全类名
association中再使用id 和result赋值
collection 专门用来映射集合 property表示映射的集合的属性名 ofType表示集合中的类型
**
一对一分布查询
**
有时候我们查询结果后只运用了某个子段 所以全部查询出来就是很浪费的 这时候可以用分布查询
代码显示地使用了哪个子段的表才查哪个
我们需要把表分成虚拟的主表和从表进行查询 所以需要写两个mapper接口和映射xml 分别查询两个表的子段 在一对一的情况下 就是第一个pojo对象为主表 pojo里面的pojo对象为从表 分两步进行查询 不使用到pojo里的pojo对象就不进行查询
使用:
association :
select属性写上第二个mapper.xml的名称空间.标签id 即第二批次执行的查询语句
column传入在第一个主表中查询出来的pojo 中的pojo的id值
此时就可以分成两个语句进行查询
还需要使用延迟加载 :
延迟加载在一定程序上可以减少很多没有必要的查询。给数据库服务器提升性能上的优化。
要启用延迟加载,需要在mybatis-config.xml配置文件中,添加如下两个全局的settings配置。
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 将积极加载改为消极加载 按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
懒加载功能,mybatis3.2.8版本,需要同时引入两个jar包
cglib-2.2.2 asm-3.3.1
全部配置好后 执行第一个查询语句的时候就会查主表 在使用到第二个表的字段的时候才会再次进行查询
**
一对多分步查询
**
查询的代码方法跟上面一对一的一样 只不过查询的是集合;
**
一对多双向关联
**
顾名思义 就是一个A对象里面有一个集合对象 集合对象里面的每一个B对象又有开头的A对象
所以在第一个懒加载里面调用了第二个对象的懒加载 第二个对象的懒加载又调用了第一个的懒加载
这里会产生一个问题:就是注意不要调用A.toString()否则会出错stackoverflowerror
需要用什么的时候 就把这个属性拿出来 手动调用
**
动态sql
**
if 可以动态的根据你的值来决定,是否需要动态的添加查询条件
where 可以帮我们在多个动态语句中,有效的去掉前面的多余的and 或 or 之类的多余关键字 还可以动态的判断中间是否包含查询条件。如果没有连where关键字也不会出现。
trim 可以动态在包含的语句前面和后面添加内容。也可以去掉前面或者后面给定的内容
prefix 前面添加内容
suffix 后面添加内容
suffixOverrides 去掉的后面内容
prefixOverrides 去掉的前面内容
choose when otherwise 可以执行多路选择判断,但是只会有一个分支会被执行。 类似switch case 语句
set 删除条件后面的逗号
foreach标签 用来遍历集合
collection遍历的数据源
open属性设置遍历的开始内容
close属性设置遍历的结束内容
item属性是当前遍历到的数据
separator属性设置遍历的每个元素之间的间隔符
**
mybatis 缓存
**
缓存:缓存指的是将经常访问的数据保存到一个高速的数据存储区,其实就是内存~ 缓存的目的当然就是为了快速访问
一级缓存(默认开启的): 指的是将数据保存在SqlSession中(同一个SqlSession)
只有在SqlSession中没有的才发送sql语句到数据库进行查询 查询回来后直接放在一级缓存中
---------------一级缓存的管理:
缓存失效的四种情况:
1.不在同一个SqlSession对象中
2.执行语句的参数不同。缓存中也不存在数据。
3.执行增,删,改,语句,会清空掉缓存(两次查询中间做了增删改查的操作~)
4.手动清空缓存数据 (调用session对象的clearCache())
二级缓存(默认不开启的!~): 指的是将数据保存以mapper中(同一个sqlSessionFactory)
因为是从sqlSessionFactory中创建出来的SqlSession对象 所以下段话很容易理解:
1先从二级缓存中查询(sqlSessionFactory对象)
2再从一级缓存中查询
3都没有才到数据库中查询 并且放到一级缓存中
4SqlSession关闭的时候把数据保存到二级缓存中~
当SqlSession执行相关的缓存失效情况时候(例如执行添加删除等操作) 就会清空一级和二级缓存~
这就意味着多个sqlSessionFactory下的SqlSession对象只要有一个查询回来数据就会保存在sqlSessionFactory中 其后的sqlSession对象查询相同数据会直接去二级缓存查询 不会像上面一样重新查询数据库了(但是不同的一级缓存sqlSession需要在其他sqlSession查询前关闭)
开启二级缓存:
myBatis的二级缓存默认是不开启的。我们需要在mybatis的核心配置文件中配置setting选项 和 在Mapper的配置文件中加入cache标签。并且需要被二级缓存的对象必须要实现java的序列化接口。
二级缓存的使用步骤:
1、在mybatis-config.xml中配置选项
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2、在Mapper.xml中去添加一个cache标签
3、对象必须要实现java的序列化接口 (因为涉及到了序列化和反序列化)
底层:是CachingExecutor内部的query方法会创建一个CacheKey对象(查询语句加参数 所以参数不同会导致缓存失效 因为key不同)
TransactionCacheManager二级缓存事务管理器以上述CacheKey为参数查询 查询不到一级执行器SimpleExecutor就会调用一级缓存localCache查询 也没有就调用queryFromDatabse查询数据库~
**
mybatis的逆向工程:
**
可以快速根据表生成对应的 bean对象 对应的mapper接口 mapper接口对应的映射文件
1写一个xml配置文件
(图片来自网络 侵删)
2写一个java类 运行:
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("你的配置文件.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
去除全部注释:
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>