MyBatisday01
Mybatis入门
为什么使用框架
- 是一个应用程序的半成品
- 提供可重用的公共结构
- 按一定规则组织的一组组件
优势:
- 不用再考虑公共部分
- 专心在业务实现上
- 结构同一,易于学习,维护
- 新手也可以写出好程序
世界上流行的框架(framework)
- Struts1\Struts2\Spring MVC\Spring Boot
- Hibernate\MyBatis
- Spring
持久化与瞬时状态
- 瞬时状态
当创建一个对象后,但没有存储到数据库中之前的一段时间状态被称为瞬时状态
- 持久状态
当一个对象被存到了磁盘上或者数据库中时,这时的状态为持久状态
事务(Transaction)
事务(Transaction),一般是指要做的或所做的事情。在计算机
默认情况下,MySQL的事务提交方式是自动提交。每一条SQL语句就是一个独立的事务
延时加载(LazyLoad)
默认情况下,框架会将某一个表的映射关系全部读取出来。如果所有的数据,在读取一张表的时候,就将所有的关联表数据全部加载出来,会造成内存使用量消耗过大,在MyBatis中提供了延迟加载,即,什么时候用到关联表数据,再发起查询,避免内存浪费。
Mybatis环境搭建
导入依赖
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency>
创建xml
全局文件配置
配置全局xml 一般叫做mybatis-config.xml
<configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> </configuration>
最简单的全局配置文件由三个部分组成:
- 数据源
// 该写法,代表调用默认的配置数据源 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is) ; // 该写法,代表调用所选的的配置数据源 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is,"dev") ;
<environments default="development"> <environment id="development"> <!--事务管理器--> <transactionManager type="JDBC"/> <!--数据源:数据连接池--> <dataSource type="POOLED"> <property name="driver" value="${oracle_driver}"/> <property name="url" value="${oracle_url}"/> <property name="username" value="${oracle_username}"/> <property name="password" value="${oracle_password}"/> </dataSource> </environment> <environment id="dev"> <!--事务管理器--> <transactionManager type="JDBC"/> <!--数据源:数据连接池--> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments>
- 事务管理
事务管理默认使用的是JDBC调用,还可以配置其他的使用方式。
- 映射文件加载
<mappers> <!--注意这里的路径要与实体类路径相对应--> <mapper resource="com/csi/domain/RoleMapper.xml" /> <mapper .../> </mappers>
映射文件
<?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:属性值在全局只能存在一个,一般普通写法都是写的对应的实体类名称--> <mapper namespace="com.csi.domain.Role"> <!-- id:代表方法名称 resultType:返回的类型 --> <select id="list" resultType="com.csi.domain.Role"> SELECT * FROM smbms_role </select> </mapper>
映射类型对应表:
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
日志文件配置(选用log4j)
log4j.rootLogger=DEBUG,CONSOLE,file
#log4j.rootLogger=ERROR,ROLLING_FILE
log4j.logger.com.csi.dao=debug
log4j.logger.com.ibatis=debug
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug
log4j.logger.java.sql.Connection=debug
log4j.logger.java.sql.Statement=debug
log4j.logger.java.sql.PreparedStatement=debug
log4j.logger.java.sql.ResultSet=debug
log4j.logger.org.tuckey.web.filters.urlrewrite.UrlRewriteFilter=debug
######################################################################################
# Console Appender \u65e5\u5fd7\u5728\u63a7\u5236\u8f93\u51fa\u914d\u7f6e
######################################################################################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=error
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= [%p] %d %c - %m%n
######################################################################################
# DailyRolling File \u6bcf\u5929\u4ea7\u751f\u4e00\u4e2a\u65e5\u5fd7\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u683c\u5f0f:log2009-09-11
######################################################################################
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern=yyyy-MM-dd
log4j.appender.file.File=log.log
log4j.appender.file.Append=true
log4j.appender.file.Threshold=error
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n
log4j.logger.com.opensymphony.xwork2=debug
Mybatis生命周期
SqlSessionFactoryBuilder
- 用过即丢,其生命周期只存在于方法体内
- 可重用其来创建多个SqlSessionFactory实例
- 负责构件SqlSessionFactory,并提供多个build方法的重载
SqlSessionFactory
- SqlSessionFactory是每个MyBatis应用的核心
- 作用:创建SqlSession实例
- 在创建SqlSession的同时,能够将事务设置为手动或者自动的
- SqlSession sqlSession = sqlSessionFactory.openSession(boolean autoCommit);
- true | false 默认为false 表示事务不自动提交
- 作用域:application
- 生命周期与应用的声明周期相同
- 单利
- 存在于整个应用运行中,并且同时只存在于一个对象实例中
SqlSession
- 包含了执行SQL所需的所有方法
- 对应一次数据库会话,会话结束必须关闭
- 线程级别,不能共享
SqlSession session = sqlSessionFactory.openSession(); try { // do work } finally { session.close(); }
在sqlSession不关闭的情况下可以多次执行sql,但关闭后SqlSession就需要重新创建
在一个方法中使用sqlsession对象执行sql后,如果再次执行相同的sql,那么后一条sql就不会再次执行,而是直接取缓存中的数据。
‘完美’的单例模式
// 单例设计 获取SqlSessionFactory对象 public class MyBatisUtil { // 声明一个 静态的 sqlSessionFactory对象 volatile->禁止指令重排序 private static SqlSessionFactory sqlSessionFactory = null; // 静态获取sqlsessionfactory工厂对象 public static SqlSessionFactory getInstance(){ System.out.println(Thread.currentThread().getName() + "....................." ); // 判断sqlSessionFactory对象是否已经实例化 如果没有则通过io流读取配置文件数据 if (sqlSessionFactory == null){ InputStream is = null; try { is = Resources.getResourceAsStream("mybatis-config.xml"); } catch (IOException e) { e.printStackTrace(); } // 设置同步代码块 进行二次判断 如果此时sqlSessionFactory对象为null 则实例化 synchronized (SqlSessionFactory.class){ if (sqlSessionFactory == null){ sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); } } } return sqlSessionFactory; } public static SqlSession getSqlSession(){ return getInstance().openSession(); } public static void close(SqlSession sqlSession){ if (sqlSession!=null){ sqlSession.close(); } } }
假如四个线程同时进入此方法,当sqlsessionFactory为null时,四个线程都会在synchronized块前阻塞,第一个进入代码块的线程会最先实例化sqlSessionFactory对象,并且取得sqlSessionFactory对象返回值,此时其他的线程获取到资源访问同步代码快中的代码,但是这是sqlSessionFactory对象已经不为null,所以其余阻塞线程都会直接获取sqlSessionFactory对象作为返回值,而不是重新使用SqlSessionFactoryBuilder().build()来创建SqlSessionFactory对象。