mybatis入门
1.mybatis概述
Mybatis是一个支持普通SQL查询、存储过程和高级映射的优秀持久层框架。Mybatis去除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。Mybatis通过使用简单的xml或注解进行配置和原始映射,将接口和java的POJO(plain old java object)映射成数据库中的记录。
mybatis作为持久层框架,主要思想是:将SQL语句和程序代码分离开来,做到不修改代码,而只是修改配置文件的SQL的灵活配置。
2.mybatis入门
2.1下载jar包
mybatis-3.3.1.jar --核心包
2.2 mybatis的数据库操作
在mysql数据库中创建一个新的表users。脚本如下:
create table tb_user( id int primary key AUTO_INCREMENT, username nvarchar(50) not null, password nvarchar(50) not null, age int, deleted INT DEFAULT 0 );
POJO类:xml/domain/User.java
package xml.domain; public class User { private int id; private String username; private String password; private int age; private Integer deleted; public Integer getDeleted() { return deleted; } public void setDeleted(Integer deleted) { this.deleted = deleted; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", age=" + age + ", deleted=" + deleted + '}'; } }
mybatis通过xml文件去完成持久化类和数据库表之间的映射关系的:
<?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="xml.mapper.UserMapper"> <!-- 根据id查询User --> <select id="selectUserById" parameterType="int" resultType="xml.domain.User" useCache='false'> SELECT * FROM TB_USER WHERE id = #{id} </select> <select id="selectUserMap" resultType="map"> SELECT * FROM TB_USER </select> <!--插入数据--> <insert id="saveUser" parameterType="xml.domain.User"> INSERT INTO tb_user(username,password,age) VALUES (#{username},#{password},#{age}) </insert> </mapper>
配置文件详细解释:
(1)<mapper namespace="xml.mapper.UserMapper">,为这个mapper指定一个唯一的namespace,namespace习惯是使用:包名+sql映射文件名,这样可以保证namespace的唯一性,例如这里的xml.mapper.UserMapper。
(2)在select和insert操作中,都使用了id属性,标识执行的操作,必须唯一,不能重复。例如:selectUserById,saveUser
(3)parameterType表示执行操作时使用的参数类型。
(4)在insert插入语句中,可以使用useGenerateKeys来指定是否使用自动增长策略。
(5)在insert语句中,#{username}表示从参数User中取出username属性。
对于mybatis来讲,现在还不知道连接哪个数据库,以及使用什么连接池等信息,配置信息如下:【mybatis配置文件默认被命名为mybatis-config.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"> <!-- XML 配置文件包含对 MyBatis 系统的核心设置 --> <configuration> <properties resource="db.properties"/> <!-- 指定 MyBatis 所用日志的具体实现 --> <settings> <setting name="logImpl" value="LOG4J"/> <!-- 开启二级缓存 --> <setting name="cacheEnabled" value="true"/> </settings> <!-- 设置别名 --> <typeAliases> <typeAlias alias="user" type="xml.domain.User"/> </typeAliases> <environments default="development"> <!-- 环境配置,即连接的数据库。 --> <environment id="development"> <!-- 指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 --> <transactionManager type="JDBC"/> <!-- dataSource指数据源配置,POOLED是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> <!-- mappers告诉了MyBatis去哪里找持久化类的映射文件 --> <mappers> <mapper resource="xml/mapper/UserMapper.xml"/> </mappers> </configuration>
db.properties:mybatis 使用<properties resource="db.properties"/>指定数据库属性
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
username=root
password=123
maxPoolSize=20
maxIdleTime = 1000
minPoolSize=6
initialPoolSize=5
log4j.properties :【日志配置】
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.xml.mapper.UserMapper=DEBUG
# 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
测试:
package xml.test; 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 org.junit.Test; import xml.domain.User; import java.io.IOException; import java.io.InputStream; public class MybatisTest { @Test public void test1() throws IOException { //读取mybatis-config.xml文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //初始化mybatis,创建SqlSessionFactory类的实例 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 创建Session实例 SqlSession session = sqlSessionFactory.openSession(); User user = new User(){{ setUsername("张三"); setPassword("123"); setAge(20); }}; int rs = session.insert("xml.mapper.UserMapper.saveUser", user); System.out.println(rs); // 提交事务 session.commit(); // 关闭session session.close(); } }
2. mybatis的基本用法
2.1 mybatis体系结构
2.1.1 SqlSessionFactory
SqlSessionFactory是mybatis的核心对象,它是单个数据库映射关系经过编译后的内存镜像。SqlSessionFactory对可以通过SqlSessionFactoryBuilder对来获得,而SqlSessionFactoryBuilder可以从xml配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory对象。每一个mybatis的应用程序都应该以一个SqlSessionFactory对象实例为核心。其线程也是安全的,SqlSessionFactory一旦被创建,应该在整个应用周期都存在,建议使用单例模式。
2.1.2 SqlSession
SqlSession是mybatis的关键对象,是执行持久化操作的对象,类似于jdbc的Statement。它的底层封装了jdbc连接,可以使用SqlSession实例来执行已经映射的SQL语句。每个线程应该有自己的SqlSession实例,该实例不能被多个线程共享,因为它不是线程安全的,绝对不能将SqlSession放在静态字段中,或者将该实例放在任何范围管理内,例如Servlet的HttpSession对象中。SqlSession使用完后一定要关闭。
常用方法如下:
int insert(String statement) | 插入方法,statement是定义在映射配置文件中的<insert />的id,返回影响行数 |
int insert(String statement, Object parameter) | 插入方法,parameter是插入时所需参数,一般为POJO或者Map |
int update(String statement[, Object paramenter) | 更新,参数同上 |
int delete(String statement[, Object paramter) | 删除,参数同上 |
<T> T selectOne(String statement[, Object param]) | 查询一个,例如:如果查不到,返回null
User u = session.selectOne("xml.mapper.UserMapper.selectUserById",1); |
<E> List<E> selectList(String statement[, Object param]) | 查询,返回一个泛型集合,例如:
List<User> users = session.selectList("xml.mapper.UserMapper.selectUserById",1); |
<E> List<E> selectList(String statement, Object param, RowBounds rowBounds) | RowBounds用于分页,他有两个属性:offset:查询的当前页数,limit:当前页显示多少条数据。 |
<K,V> Map<K, V> selectMap(string statement, String mapKey) | 返回一个Map对象,mapKey是一个表的列名,Map结果的key就是参数mapKey,value是封装的对象。 |
<K,V> Map<K, V> selectMap(string statement, Object parameter,String mapKey) | |
<K,V> Map<K, V> selectMap(string statement, Object parameter,String mapKey,RowBounds rowBounds) | |
void select(String statement, ResultHandler handler) | ResultHandler对象用来处理查询返回的复杂结果,通常用来多表查询 |
void select(String statement, Object parameter, ResultHandler handler) | |
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) | |
void commit() | |
void rollback() | 事务回滚 |
void close() | |
Connection getConnection() | |
<T> T getMapper(Class<T> type) | 返回mapper接口的代理对象,该对象关联了SqlSession对象,可以通过该对象直接调用方法操作数据库。 |
2.2 深入mybatis的配置文件
回顾SqlSession的初始化过程:
//读取mybatis-config.xml文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //初始化mybatis,创建SqlSessionFactory类的实例 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 开始初始化mybatis // 创建Session实例 SqlSession session = sqlSessionFactory.openSession();
mybatis 初始化的基本过程:
- SqlSessionFactoryBuilder根据传入的数据流超声Configuration对象,然后根据Configuration对象创建默认的SqlSessionFactory实例。
2.2.1 mybatis配置文件结构
<?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"> <!-- XML 配置文件包含对 MyBatis 系统的核心设置 --> <configuration> <properties resource="db.properties"/> <!-- 指定 MyBatis 所用日志的具体实现 --> <settings> <setting name="logImpl" value="LOG4J"/> <!-- 开启二级缓存 --> <setting name="cacheEnabled" value="true"/> </settings> <!-- 设置别名 --> <typeAliases> <typeAlias alias="user" type="xml.domain.User"/> </typeAliases> <environments default="development"> <!-- 环境配置,即连接的数据库。 --> <environment id="development"> <!-- 指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 --> <transactionManager type="JDBC"/> <!-- dataSource指数据源配置,POOLED是JDBC连接对象的数据源连接池的实现。 --> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${user}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!-- mappers告诉了MyBatis去哪里找持久化类的映射文件 --> <mappers> <mapper resource="xml/mapper/UserMapper.xml"/> </mappers> </configuration>
顶级configuration配置:
- properties属性 例如<properties resource="db.properties" /> 读取该文件的数据
- settings设置
- typeAliases 类型别名
- typeHandler 类型处理器
- objectFactory 对象工程
- plugins 插件
- environments 环境
- environment 环境变量
- transactionManager 事务管理器
- dataSource 数据源
- databaseIdProvider 数据库厂商标识
- mappers 映射器
settings大全:
设置参数 | 描述 | 有效值 | 默认值 |
cacheEnabled | 该配置影响的所有映射器中配置的缓存的全局开关 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态 | true | false | false |
aggressiveLazyLoading | 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载。 | true | false | true |
multipleResultSetsEnabled | 是否允许单一语句返回多结果集(需要兼容驱动)。 | true | false | true |
useColumnLabel | 使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 | true | false | False |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数。 | Any positive integer | Not Set (null) |
defaultFetchSize | Sets the driver a hint as to control fetching size for return results. This parameter value can be override by a query setting. | Any positive integer | Not Set (null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用分页(RowBounds)。 | true | false | False |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。 | SESSION | STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 | JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER | OTHER |
lazyLoadTriggerMethods | 指定哪个对象的方法触发一次延迟加载。 | A method name list separated by commas | equals,clone,hashCode,toString |
defaultScriptingLanguage | 指定动态 SQL 生成的默认语言。 | A type alias or fully qualified class name. | org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver |
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。 | true | false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | Any String | Not set |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | Not set |
proxyFactory | 指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 or above) |
2.3 深入Mapper XML的映射文件
SQL映射文件常用的元素如下:
- select
- insert
- update
- delete
- sql:可被其它语句引用的可重用语句块
- cache:给定命名空间的缓存配置
- cache-ref:其它命名空间缓存配置的引用
- resultMap :最复杂也是最强大的元素,用来描述如何从数据库结果集中加载对象。
(1)select
<select id="selectUserById" parameterType="int" resultType="xml.domain.User" useCache='false'> SELECT * FROM tb_user WHERE id = #{id} </select>
这个语句被称为selectUserById,接受一个int(或者Integer)类型的参数,并返回一个User对象。
resultType可以为hashmap:key为列名,value为对应的值。
#{id}:告诉mybatis创建一个预处理语句参数:会生成如下JDBC代码:
String sql = "select * from tb_user where id = ? "; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, id);
select元素的属性:
- id:命名空间的唯一标识
- parameterType:传入这条语句的参数类的全限定名或列名。这个属性是可选的,因为TypeHandler可以推断出具体传入语句的参数,默认值为unset
- resultType:返回的期望类型的权限定名或列名。
- resultMap:外部resultMap的命名引用。resultType和resultMap二者不可同时出现
- flushCache:如果设置为true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值为false。
- useCache:如果为true,将会导致本条语句的结果被二级缓存,在select中默认为true。
- timeout:超时等待时间
- fetchSize:
- statementType:值为STATEMENT, PREPARED或CALLABLE。这回让mybatis分别使用Statement、preparedStatement或CallableStatement,默认为PREPARED.
- resultSetType:返回结果集的类型,值为:FORWARD_ONLY,SCROLL_SENSITIVE,SCROLL_INSENSITIVE
- databaseId:
- resultOrdered
- resultSets
(2)insert、update和delete元素的属性大多和select一致,他们的特性如下:
- useGenerateKeys(仅对insert和update有用):主键自增长
- keyPropery(仅对insert和update有用):唯一标记一个属性,
- keyColumn(仅对insert和update有用):
返回插入成功的数据的主键值:
1>对于Mysql和SQLserver这样支持主键自增长的数据库,可以将useGenerateKeys="true", keyProperty="id"【目标属性】即可。
必须要同时设置两个属性,否则User的id不会被自动封装进去:
<!--插入数据--> <insert id="saveUser" parameterType="xml.domain.User" useGeneratedKeys="true" keyProperty="id"> INSERT INTO tb_user(username,password,age) VALUES (#{username},#{password},#{age}) </insert>
测试:
System.out.println("插入前:"+user); int rs = session.insert("xml.mapper.UserMapper.saveUser", user); System.out.println("插入后:"+user); System.out.println("影响行数:"+rs);
2>对于不支持自动生成类型的数据库(如Oracle)或者不支持自动生成主键的JDBC驱动来说:
(3) sql
sql元素可以被用来定义可重用的SQL代码段,可以包含在其他语句中。它可以被静态的参数化。
(4) 参数 [parameterType]
对于原生【基本】类型,如:int,string,long,date等,直接替换
对于复杂类型。如:User类,Map类型,取其属性名映射到动态参数上。
7
end