MyBatis的核心配置
1、MyBatis的核心对象
1)、SqlSessionFactory是MyBatis框架中十分重要的对象,它是单个数据库映射关系经过编译后的内存镜像,其主要作用是创建SqlSession。
2)、SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象来构建,而SqlSessionFactoryBuilder则可以通过XML配置文件或一个预先定义好的Configuration实例构建出SqlSessionFactory的实例。
3)、构建SqlSessionFactory
a)、通过XML配置文件构建出的SqlSessionFactory实例现代码如下:
InputStream inputStream = Resources.getResourceAsStream("配置文件位置"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 根据配置文件构建SqlSessionFactory
b)、SqlSessionFactory对象是线程安全的,它一旦被创建,在整个应用执行期间都会存在。如果我们多次的创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽。为此,通常每一个数据库都会只对应一个SqlSessionFactory,所以在构建SqlSessionFactory实例时,建议使用单列模式。
d)、单例模式:是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象实例。
4)、SqlSession是MyBatis框架中另一个重要的对象,它是应用程序与持久层之间执行交互操作的一个单线程对象,其主要作用是执行持久化操作。SqlSessionu对象包含了数据库中所有执行SQL操作的方法,由于底层封装了JDBC连接,所以可以直接使用其实例来执行已映射的SQL语句。
5)、每一个线程都应该有一个自己的SqlSession实例,并且该实例是不能被共享的。同时,SqlSession实例也是线程不安全的,因此其使用范围最好在一次请求或一个方法中,绝不能将其放在一个类的静态字段、实例字段或任何类型的管理范围(如Servlet的HttpSession)中使用。
使用完SqlSession对象后要及时关闭,通常可以将其放在finally块中关闭。 SqlSession sqlSession = sqlSessionFactory.openSession(); try { // 此处执行持久化操作 } finally { sqlSession.close(); }
6)、SqlSession中的方法:
查询方法:
T selectOne(String statement); T selectOne(String statement, Object parameter); List selectList(String statement); List selectList(String statement, Object parameter); List selectList(String statement, Object parameter, RowBounds rowBounds);
void select(String statement, Object parameter, ResultHandler handler);插入、更新和删除方法:(返回值为执行SQL语句所影响的行数)
int insert(String statement);
int insert(String statement, Object parameter);
int update(String statement);
int update(String statement, Object parameter);
int delete(String statement);
int delete(String statement, Object parameter);其他方法:
void commit(); 提交事务的方法。
void rollback(); 回滚事务的方法。
void close(); 关闭SqlSession对象。T getMapper(Class type); 返回Mapper接口的代理对象。
Connection getConnection(); 获取JDBC数据库连接对象的方法。
7)、为了简化开发,通常在实际项目中都会使用工具类来创建SqlSession。
a)、src->MybatisUtils.java
1 package com.itheima.utils; 2 import java.io.Reader; 3 import org.apache.ibatis.io.Resources; 4 import org.apache.ibatis.session.SqlSession; 5 import org.apache.ibatis.session.SqlSessionFactory; 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 /** 8 * 工具类,简化代码 9 */ 10 public class MybatisUtils { 11 12 private static SqlSessionFactory sqlSessionFactory = null; 13 14 // 1、初始化SqlSessionFactory对象工厂(只创建了一个) 15 static { 16 try { 17 18 // 2、使用MyBatis提供的Resources类加载MyBatis的配置文件 19 Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); 20 21 // 3、构建SqlSessionFactory工厂 22 sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); 23 24 } catch (Exception e) { 25 e.printStackTrace(); 26 } 27 } 28 29 // 4、通过getSession()方法获取SqlSession对象的静态方法 30 public static SqlSession getSession() { 31 return sqlSessionFactory.openSession(); 32 } 33 }
2、配置文件
1)、主要元素:在MyBatis框架的核心配置文件中,
注意:这些子元素必须按照由上到下的顺序进行配置,否则MyBatis在解析XML配置文件的时候会报错。
2)、
a)、
b)、src->db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=******#密码自己设置
c)、在MyBatis配置文件mybatis-config.xml中配置
<properties resource="db.properties" />
d)、修改配置文件中数据库连接的信息dataSource中连接数据库的4个属性(driver,url、username和password)值将会由db.properties文件中对应的值来动态替换。
<dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> dataSource>
3)、
a)、
b)、
...
c)、
d)、使用
e)、当POJO类过多时,可以通过自动扫描包的形式自定义别名,具体如下:(注意别名不区分大小写,会导致重复定义覆盖问题)
注意:上述方式的别名只适用于没有使用注解的情况。如果在程序中使用了注解,则别名为其注解的值。
f)、MyBatis框架默认为许多常见的Java类型提供了相应的类型别名,如下表所示。
4)、
a)、typeHandler的作用就是将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型),或者从数据库取出结果时将jdbcType转换为javaType。
b)、
①注册一个类的类型处理器:
②注册一个包中所有的类型处理器:
5)、
a)、MyBatis框架每次创建结果对象的新实例时,都会使用一个对象工厂(ObjectFactory)的实例来完成。MyBatis中默认的ObjectFactory的作用是实例化目标类,它既可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化。通常使用默认的ObjectFactory即可。
b)、大部分场景下都不用配置和修改默认的ObjectFactory ,如果想覆盖ObjectFactory的默认行为,可以通过自定义ObjectFactory来实现,具体如下:
1 package com.itheima.factory; 2 import java.util.Collection; 3 import java.util.List; 4 import java.util.Properties; 5 6 import org.apache.ibatis.reflection.factory.DefaultObjectFactory; 7 8 //自定义工厂类 9 public class MyObjectFactory extends DefaultObjectFactory { 10 private static final long serialVersionUID = -4114845625429965832L; 11 publicT create(Class type) { 12 return super.create(type); 13 } 14 public T create(Class type, List > constructorArgTypes, List
c)、在配置文件中使用
<objectFactory type="com.itheima.factory.MyObjectFactory"> <property name="name" value="MyObjectFactory"/> objectFactory>
6)、
MyBatis允许在已映射语句执行过程中的某一点进行拦截调用,这种拦截调用是通过插件来实现的。
7)、
a)、
b)、使用
1 <environments default="development"> 2 10 <environment id="development"> 11 12 <transactionManager type="JDBC" /> 13 14 <dataSource type="POOLED"> 15 <property name="driver" value="${jdbc.driver}" /> 16 <property name="url" value="${jdbc.url}" /> 17 <property name="username" value="${jdbc.username}" /> 18 <property name="password" value="${jdbc.password}" /> 19 dataSource> 20 environment> 21 ... 22 environments>
c)、在MyBatis中,可以配置两种类型的事务管理器,分别是JDBC和MANAGED。关于这两个事务管理器的描述如下:
JDBC:此配置直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务的作用域。
MANAGED:此配置从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。默认情况下,它会关闭连接,但一些容器并不希望这样,为此可以将closeConnection属性设置为false来阻止它默认的关闭行为。
注意:如果项目中使用的是Spring+ MyBatis,则没有必要在MyBatis中配置事务管理器,因为实际开发中,会使用Spring自带的管理器来实现事务管理。
d)、数据源的配置:
①UNPOOLED:配置此数据源类型后,在每次被请求时会打开和关闭连接。它对没有性能要求的简单应用程序是一个很好的选择。在使用时,需要配置5种属性。
②POOLED:此数据源利用“池”的概念将JDBC连接对象组织起来,避免了在创建新的连接实例时所需要初始化和认证的时间。POOLED数据源可额外配置的属性。
③JNDI:可以在EJB或应用服务器等容器中使用。容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。在使用时,需要配置2个属性。
8)、
a)、
①使用类路径引入(name)
②使用本地文件路径引入(url)
③使用接口类引入(class)
3、映射文件
1)、在映射文件中,
2)、
a)、
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer"> select * from t_customer where id = #{id} select>
b)、
c)、
<insert id="addCustomer" parameterType="com.itheima.po.Customer" flushCache="true" statementType="PREPARED" insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) insert>
①客户持久化类:Customer.java
1 package com.itheima.po; 2 /** 3 * 客户持久化类 4 */ 5 public class Customer { 6 7 private Integer id; // 主键id 8 private String username; // 客户名称 9 private String jobs; // 职业 10 private String phone; // 电话 11 12 public Integer getId() { 13 return id; 14 } 15 16 public void setId(Integer id) { 17 this.id = id; 18 } 19 20 public String getUsername() { 21 return username; 22 } 23 24 public void setUsername(String username) { 25 this.username = username; 26 } 27 28 public String getJobs() { 29 return jobs; 30 } 31 public void setJobs(String jobs) { 32 this.jobs = jobs; 33 } 34 35 public String getPhone() { 36 return phone; 37 } 38 39 public void setPhone(String phone) { 40 this.phone = phone; 41 } 42 @Override 43 public String toString() { 44 return "Customer [id=" + id + ", username=" + username + ", jobs=" + jobs + ", phone=" + phone + "]"; 45 } 46 }
②客户映射文件:CustomerMapper.xml
1 xml version="1.0" encoding="UTF-8"?> 2 DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 6 <mapper namespace="com.itheima.mapper.CustomerMapper"> 7 8 9 10 11 12 13 14 15 <select id="findCustomerByName" parameterType="String" 16 resultType="com.itheima.po.Customer"> 17 select * from t_customer where username like '%${value}%' 18 select> 19 20 24 <insert id="addCustomer" parameterType="com.itheima.po.Customer" 25 keyProperty="id" useGeneratedKeys="true"> 26 insert into t_customer(username,jobs,phone) 27 values(#{username},#{jobs},#{phone}) 28 insert> 29 30 37 <insert id="insertCustomer" parameterType="com.itheima.po.Customer"> 38 <selectKey keyProperty="id" resultType="Integer" order="BEFORE"> 39 select if(max(id) is null, 1, max(id) +1) as newId from t_customer 40 selectKey> 41 insert into t_customer(id,username,jobs,phone) 42 values(#{id},#{username},#{jobs},#{phone}) 43 insert> 44 45 46 <update id="updateCustomer" parameterType="com.itheima.po.Customer"> 47 update t_customer 48 set username=#{username},jobs=#{jobs},phone=#{phone} 49 where id=#{id} 50 update> 51 52 53 <delete id="deleteCustomer" parameterType="Integer"> 54 delete from t_customer where id=#{id} 55 delete> 56 57 58 59 60 61 62 63 64 65 66 67 <sql id="tablename"> 68 ${prefix}customer 69 sql> 70 71 72 <sql id="someinclude"> 73 from 74 <include refid="${include_target}" /> 75 sql> 76 77 78 <sql id="customerColumns"> 79 id,username,jobs,phone 80 sql> 81 82 83 <select id="findCustomerById" parameterType="Integer" 84 resultType="com.itheima.po.Customer"> 85 select 86 <include refid="customerColumns"/> 87 <include refid="someinclude"> 88 <property name="prefix" value="t_" /> 89 <property name="include_target" value="tablename" /> 90 include> 91 where id = #{id} 92 select> 93 94 mapper>
③配置文件:mybatis-config.xml
1 xml version="1.0" encoding="UTF-8" ?> 2 DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 3 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 4 5 <configuration> 6 7 <properties resource="db.properties" /> 8 9 10 14 15 16 19 20 21 <environments default="mysql"> 22 23 24 <environment id="mysql"> 25 26 27 <transactionManager type="JDBC" /> 28 29 30 <dataSource type="POOLED"> 31 32 33 <property name="driver" value="${jdbc.driver}" /> 34 35 36 <property name="url" value="${jdbc.url}" /> 37 38 39 <property name="username" value="${jdbc.username}" /> 40 41 42 <property name="password" value="${jdbc.password}" /> 43 44 dataSource> 45 environment> 46 environments> 47 48 49 <mappers> 50 <mapper resource="com/itheima/mapper/CustomerMapper.xml" /> 51 <mapper resource="com/itheima/mapper/UserMapper.xml" /> 52 mappers> 53 configuration>
④测试单元:
1 @Test 2 public void addCustomerTest(){ 3 4 // 通过工具类获取SqlSession 5 SqlSession sqlSession = MybatisUtils.getSession(); 6 Customer customer = new Customer(); 7 customer.setUsername("NOOo"); 8 customer.setJobs("programmer"); 9 customer.setPhone("22525323392"); 10 11 // 使用主键自助增长的添加方法 12 int rows = sqlSession.insert("com.itheima.mapper.CustomerMapper.addCustomer", customer); 13 14 // 使用自定义主键值的添加方法 15 // int rows = sqlSession.insert("com.itheima.mapper.CustomerMapper.insertCustomer", customer); 16 17 // 输出插入数据的主键id值 18 System.out.println(customer.getId()); 19 if(rows > 0){ 20 System.out.println("您成功插入了"+rows+"条数据!"); 21 }else{ 22 System.out.println("执行插入操作失败!!!"); 23 } 24 25 sqlSession.commit(); 26 sqlSession.close(); 27 }
g)、运行结果:
h)、对于不支持主键自助增长的数据库(如Oracle),可以通过如下配置实现:
<insert id="insertCustomer" parameterType="com.itheima.po.Customer"> <selectKey keyProperty="id" resultType="Integer" order="BEFORE"> select if(max(id) is null, 1, max(id) +1) as newId from t_customer selectKey> insert into t_customer(id,username,jobs,phone) values(#{id},#{username},#{jobs},#{phone}) insert>
j)、运行结果:
3)、
<update id="updateCustomer" flushCache="true" statementType="PREPARED" timeout="20"> <delete id="deleteCustomer" parameterType="com.itheima.po.Customer" flushCache="true" statementType="PREPARED" timeout="20">
a)、update和delete的配置代码如下:(注意执行完成之后会返回一个表示影响记录条数的整数)
<update id="updateCustomer" parameterType="com.itheima.po.Customer"> update t_customer set username=#{username},jobs=#{jobs},phone=#{phone} where id=#{id} update>
<delete id="deleteCustomer" parameterType="Integer"> delete from t_customer where id=#{id} delete>
4)、
a)、定义一个包含id、username、jobs和phone字段的代码片段如下:
<sql id="customerColumns">id,username,jobs,phonesql>
b)、上述代码片段可以包含在其他语句中使用,具体如下:通过
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer"> select <include refid="customerColumns"/> from t_customer where id = #{id} select>
c)、定义sql片段:使用
1 2 <sql id="tablename"> 3 ${prefix}customer 4 sql> 5 6 7 <sql id="someinclude"> 8 from 9 <include refid="${include_target}" /> 10 sql> 11 12 13 <sql id="customerColumns"> 14 id,username,jobs,phone 15 sql> 16 17 18 <select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer"> 19 select 20 <include refid="customerColumns"/> 21 22 <include refid="someinclude"> 23 <property name="prefix" value="t_" /> 24 <property name="include_target" value="tablename" /> 25 include> 26 where id = #{id} 27 select>
5)、
a)、
b)、
1 <resultMap type="" id=""> 2 <constructor> 3 4 5 <idArg/> 6 7 8 <arg/> 9 10 11 constructor> 12 13 <id/> 14 15 16 <result/> 17 18 19 <association property="" /> 20 21 22 <collection property="" /> 23 24 25 <discriminator javaType=""> 26 27 28 <case value="" /> 29 30 discriminator> 31 resultMap>
c)、在mybatis数据库中,创建t_user表:
CREATE TABLE t_user( t_id INT PRIMARY KEY AUTO_INCREMENT, t_name VARCHAR(50), t_age INT ); INSERT INTO t_user(t_name, t_age) VALUES('Lucy', 25); INSERT INTO t_user(t_name, t_age) VALUES('Lili', 20); INSERT INTO t_user(t_name, t_age) VALUES('Jim', 20);
①创建持久化类:User.java
1 package com.itheima.po; 2 3 public class User { // POJO 4 5 private Integer id; 6 private String name; 7 private Integer age; 8 9 public Integer getId() { 10 return id; 11 } 12 13 public void setId(Integer id) { 14 this.id = id; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public Integer getAge() { 26 return age; 27 } 28 29 public void setAge(Integer age) { 30 this.age = age; 31 } 32 33 @Override 34 public String toString() { 35 return "User [id=" + id + ", name=" + name + ", age=" + age + "]"; 36 } 37 }
②创建映射文件:UserMapper.xml
1 xml version="1.0" encoding="UTF-8"?> 2 DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 3 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 4 5 6 <mapper namespace="com.itheima.mapper.UserMapper"> 7 8 12 <resultMap type="com.itheima.po.User" id="resultMapID"> 13 14 21 <id property="id" column="t_id"/> 22 <result property="name" column="t_name"/> 23 <result property="age" column="t_age"/> 24 resultMap> 25 26 27 <select id="findAllUser" resultMap="resultMapID"> 28 select * from t_user 29 select> 30 mapper>
③测试单元:
1 @Test 2 public void findAllUserTest() { 3 4 // 通过工具类获取SqlSession 5 SqlSession sqlSession = MybatisUtils.getSession(); 6 7 // SqlSession执行映射文件中定义的SQL,并返回映射结果集合 8 Listlist = sqlSession.selectList("com.itheima.mapper.UserMapper.findAllUser"); 9 10 for (User user : list) { 11 System.out.println(user); 12 } 13 14 // 关闭SqlSession 15 sqlSession.close(); 16 }
④运行结果:
个人总结:
本章主要讲mybatis的核心配置,内容比较多,需要反复看并且经常操作才能熟练运用和理解应用程序到数据库之间的映射的详细过程。总之,先把配置文件config.xml配置好,其次再创建持久化类,并编写对应的映射文件(将持久化类中属性与数据库中表的属性列对应起来),剩下的就是简单的测试了。
注意:①使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以成功映射;②若查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做一个映射关系。