Java EE学习笔记(七)
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> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
<E> List<E> 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> T getMapper(Class<T> 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框架的核心配置文件中,<configuration>元素是配置文件的根元素,其他元素都要在<configuration>元素内配置。
注意:这些子元素必须按照由上到下的顺序进行配置,否则MyBatis在解析XML配置文件的时候会报错。
2)、<properties>元素
a)、<properties>是一个配置属性的元素,该元素通常用来将内部的配置外在化,即通过外部的配置来动态的替换内部定义的属性。例如,数据库的连接等属性,就可以通过典型的Java属性文件中的配置来替换,具体方式如下:
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... />元素:(相当于C语言的宏定义)
<properties resource="db.properties" />
d)、修改配置文件中数据库连接的信息dataSource中连接数据库的4个属性(driver,url、username和password)值将会由db.properties文件中对应的值来动态替换。
<dataSource type="POOLED"> <!-- 数据库驱动 --> <property name="driver" value="${jdbc.driver}" /> <!-- 连接数据库的url --> <property name="url" value="${jdbc.url}" /> <!-- 连接数据库的用户名 --> <property name="username" value="${jdbc.username}" /> <!-- 连接数据库的密码 --> <property name="password" value="${jdbc.password}" /> </dataSource>
3)、<settings>元素
a)、<settings>元素主要用于改变MyBatis运行时的行为,例如开启二级缓存、开启延迟加载等。
b)、<settings>元素中的常见配置在配置文件中的使用方式如下:
<!-- 设置 -->
<settings>
<setting name="cacheEnabled" value="true" />
<setting name="lazyLoadingEnabled" value="true" />
<setting name="multipleResultSetsEnabled" value="true" />
<setting name="useColumnLabel" value="true" />
<setting name="useGeneratedKeys" value="false" />
<setting name="autoMappingBehavior" value="PARTIAL" />
...
</settings>
c)、<typeAliases>元素用于为配置文件中的Java类型设置一个简短的名字,即设置别名。别名的设置与XML配置相关,其使用的意义在于减少全限定类名的冗余(含有绝对路径的名称)。
d)、使用<typeAliases>元素配置别名的方法如下:
<typeAliases>
<!--<typeAliases>元素的子元素<typeAlias>中的type属性用于指定需要被定义别名的类的全限定名,
alias属性的属性值user就是自定义的别名,它可以替代com.itheima.po.User使用在MyBatis文件的任何位置。
若省略了alias属性,MyBatis会默认将类名首字母小写后的名称作为别名。
-->
<typeAlias alias="user" type="com.itheima.po.User"/>
</typeAliases>
e)、当POJO类过多时,可以通过自动扫描包的形式自定义别名,具体如下:(注意别名不区分大小写,会导致重复定义覆盖问题)
<typeAliases>
<!--<typeAliases>元素的子元素<package>中的name属性用于指定要被定义别名的包,
MyBatis会将所有com.itheima.po包中的POJO类以首字母小写的非限定类名(如:String)来作为它的别名,
比如com.itheima.po.User的别名为user,com.itheima.po.Customer的别名是customer等。
-->
<package name="com.itheima.po"/>
</typeAliases>
注意:上述方式的别名只适用于没有使用注解的情况。如果在程序中使用了注解,则别名为其注解的值。
f)、MyBatis框架默认为许多常见的Java类型提供了相应的类型别名,如下表所示。
4)、<typeHandler>元素
a)、typeHandler的作用就是将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型),或者从数据库取出结果时将jdbcType转换为javaType。
b)、<typeHandler>元素可以在配置文件中注册自定义的类型处理器,它的使用方式有两种。
①注册一个类的类型处理器:
<typeHandlers>
<!--子元素<typeHandler>的Handle属性用于指定在程序中自定义的类型处理器类-->
<typeHandler handler="com.itheima.type.CustomtypeHandler" />
</typeHandlers>
②注册一个包中所有的类型处理器:
<typeHandlers>
<!--子元素<package>的name属性用于指定类型处理器所在的包名,
使用此种方式后,系统会在启动时自动地扫描com.itheima.type包下所有的文件,并把它们作为类处理器。
-->
<package name="com.itheima.type" />
</typeHandlers>
5)、<objectFactory>元素
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 public <T> T create(Class<T> type) { 12 return super.create(type); 13 } 14 public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { 15 return super.create(type, constructorArgTypes, constructorArgs); 16 } 17 public void setProperties(Properties properties) { 18 super.setProperties(properties); 19 } 20 public <T> boolean isCollection(Class<T> type) { 21 return Collection.class.isAssignableFrom(type); 22 } 23 }
c)、在配置文件中使用<objectFactory>元素配置自定义的ObjectFactory,配置如下:
<objectFactory type="com.itheima.factory.MyObjectFactory"> <property name="name" value="MyObjectFactory"/> </objectFactory>
6)、<plugins>元素
MyBatis允许在已映射语句执行过程中的某一点进行拦截调用,这种拦截调用是通过插件来实现的。<plugins>元素的作用就是配置用户所开发的插件。
7)、<environments>元素
a)、<environments>元素用于对环境进行配置。MyBatis的环境配置实际上就是数据源的配置,我们可以通过<environments>元素配置多种数据源,即配置多种数据库。
b)、使用<environments>元素进行环境配置的示例如下:
1 <environments default="development"> 2 <!-- default属性,用于指定默认的环境ID 3 <environment>是<environments>元素的子元素,可以定义多个, 4 其id属性用于表示所定义环境的ID值,其内包括事物管理和数据源的配置信息, 5 <transactionManager>元素用于配置事务管理, 6 type属性用于指定事务管理的方式,即使用哪种事物管理器; 7 <dataSource>元素用于配置数据源, 8 type属性用于指定使用哪种数据源。 9 --> 10 <environment id="development"> 11 <!-- 使用JDBC事物管理 --> 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)、<mappers>元素
a)、<mappers>元素用于指定MyBatis映射文件的位置,一般可以使用以下4种方法引入映射器文件,具体如下。
①使用类路径引入(name)
<mapper>
<mapper resource = "com/itheima/mapper/UserMapper.xml"/>
</mapper>
②使用本地文件路径引入(url)
<mappers>
<mapper url="E:\eclipse开发项目学习\chapter07\src\com\itheima\mapper"/>
</mappers>
③使用接口类引入(class)
<mappers>
<mapper class="com.itheima.mapper.UserMapper"/>
</mappers>
3、映射文件
1)、在映射文件中,<mapper>元素是映射文件的根元素,其他元素都是它的子元素,映射文件的主要元素如下:
2)、<select>元素
a)、<select>元素用来映射查询语句,它可以帮助我们从数据库中读取出数据,并组装数据给业务开发人员,使用<select>元素执行查询操作非常简单,其示例如下:
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer"> select * from t_customer where id = #{id} </select>
b)、<select>元素的常用属性:
c)、<insert>元素,配置如下:
<insert id="addCustomer" parameterType="com.itheima.po.Customer" flushCache="true" statementType="PREPARED" <!-- prepared预编译 --> keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20">
d)、<insert>元素的属性:<insert>元素的属性与<select>元素的属性大部分相同,但还包含了3个特有属性,这3个属性的描述如下所示。(都是仅对insert和update有用)
执行插入操作后,很多时候需要返回插入成功的数据生成的主键值,此时就可以通过上面讲解的3个属性来实现。
e)、对于支持主键自动增长的数据库(如MySQL、SQL sever),可以通过如下配置实现:
主键自动增长:对于一个表中的主键可以定义为自增长的,当主键定义为自增长后,那么这个主键的值就不需要用户输入数据,而由数据库系统根据定义自动赋值。当增加一条记录时,主键自动地以相同的步长来进行增长,这个步长是在建表的时候用户自己定义的。一般自增长数据只能是数值类型,如:int、bigint、decimal、等。
通过keyProperty属性指定PO类的某个属性接收主键返回值(通常会设置到id属性上),然后将useGeneratedKeys的属性设置为true。
<insert id="addCustomer" parameterType="com.itheima.po.Customer" keyProperty="id" useGeneratedKeys="true" > <!-- 使用JDBC的useGeneratedKeys()方法来获取由数据库内部生产的主键 --> 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 <!-- <mapper>是根元素,包括一个属性namespace表示命名空间,通常会设置成“包名+SQL映射文件名”的形式 --> 6 <mapper namespace="com.itheima.mapper.CustomerMapper"> 7 8 <!--1.根据客户编号获取客户信息 --> 9 <!-- <select id="findCustomerById" parameterType="Integer" --> 10 <!-- resultType="com.itheima.po.Customer"> --> 11 <!-- select * from t_customer where id = #{id} --> 12 <!-- </select> --> 13 14 <!--2.根据客户名模糊查询客户信息列表 --> 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 <!-- 3.添加客户信息 21 通过keyProperty属性指定PO类的某个属性接收主键返回值(通常会设置到id属性上), 22 然后将useGeneratedKeys的属性设置为true。 23 --> 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 <!-- 对于不支持自动生成主键的数据库(如oracle), 31 或者支持增长的数据库取消了主键自增的规则,可以自定义主键生成规则。 32 keyProperty:将返回的主键放入传入参数的Id中保存。 33 order:当前函数相对于insert语句的执行顺序,在insert前执行是before,在insert后执行是AFTER 34 resultType:id的类型,也就是keyproperties中属性的类型 35 执行以下代码时<selectKey>元素会首先执行,它会通过定义的语句来设置数据表中的主键,然后再调用插入语句 36 --> 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 <!-- 4.更新客户信息 --> 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 <!-- 5.删除客户信息 --> 53 <delete id="deleteCustomer" parameterType="Integer"> 54 delete from t_customer where id=#{id} 55 </delete> 56 57 <!--定义代码片段 --> 58 <!-- <sql id="customerColumns">id,username,jobs,phone</sql> --> 59 <!-- <select id="findCustomerById" parameterType="Integer" --> 60 <!-- resultType="com.itheima.po.Customer"> --> 61 <!-- select <include refid="customerColumns"/> --> 62 <!-- from t_customer --> 63 <!-- where id = #{id} --> 64 <!-- </select> --> 65 66 <!--定义表的前缀名,进行传参组合表名 --> 67 <sql id="tablename"> 68 ${prefix}customer 69 </sql> 70 71 <!--定义要查询的表,属性id为唯一标识符 --> 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 <!--根据id查询客户信息 --> 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 <!-- <typeAliases> 11 <typeAlias alias="user" type="com.itheima.po.User" /> 12 <package name="com.itheima.po" /> 13 </typeAliases> --> 14 15 <!-- 配置自定义工厂 --> 16 <!-- <objectFactory type="com.itheima.factory.MyObjectFactory"> 17 <property name="name" value="MyObjectFactory"/> 18 </objectFactory> --> 19 20 <!--1.配置环境 ,默认的环境id为mysql --> 21 <environments default="mysql"> 22 23 <!--1.2.配置id为mysql的数据库环境 --> 24 <environment id="mysql"> 25 26 <!-- 使用JDBC的事务管理 --> 27 <transactionManager type="JDBC" /> 28 29 <!--数据库连接池 --> 30 <dataSource type="POOLED"> 31 32 <!-- 数据库驱动 --> 33 <property name="driver" value="${jdbc.driver}" /> 34 35 <!-- 连接数据库的url --> 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 <!--2.配置Mapper的位置 --> 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"> <!-- <selectKey>元素会首先运行,若没有记录,则将id设置为1, 否则取id的最大值加1,来作为新的主键,然后再调用插入语句 --> 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>和<delete>元素
<update id="updateCustomer" <!-- 命名空间的唯一标识符号 --> parameterType="com.itheima.po.Customer" <!-- 参数类类型 --> 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)、<sql>元素:<sql>元素的作用就是定义可重用的SQL代码片段,然后在其他语句中引用这一代码片段。
a)、定义一个包含id、username、jobs和phone字段的代码片段如下:
<sql id="customerColumns">id,username,jobs,phone</sql>
b)、上述代码片段可以包含在其他语句中使用,具体如下:通过<include>元素的refid属性引用id为someinclude的代码片段,先加入from,再通过获取<property>元素的值来组成表名
<select id="findCustomerById" parameterType="Integer" resultType="com.itheima.po.Customer"> select <include refid="customerColumns"/> <!-- <include>元素的refid属性引用了自定义的代码片段,其值为对应的id值 --> from t_customer where id = #{id} </select>
c)、定义sql片段:使用<include>元素的refid属性引用了自定义代码片段。
1 <!--定义表的前缀名,进行传参组合表名 --> 2 <sql id="tablename"> 3 ${prefix}customer 4 </sql> 5 6 <!--定义要查询的表,属性id为唯一标识符 --> 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 <!--根据id查询客户信息 --> 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)、<resultMap>元素
a)、<resultMap>元素表示结果映射集,是MyBatis中最重要也是最强大的元素。它的主要作用是定义映射规则、级联的更新以及定义类型转化器等。
b)、<resultMap>元素中包含了一些子元素,它的元素结构如下所示:
1 <resultMap type="" id=""> 2 <constructor> 3 <!-- 类在实例化时,用来注入结果到构造方法中--> 4 5 <idArg/> 6 <!-- ID参数;标记结果作为ID--> 7 8 <arg/> 9 <!-- 注入到构造方法的一个普通结果--> 10 11 </constructor> 12 13 <id/> 14 <!-- 用于表示哪个列是主键--> 15 16 <result/> 17 <!-- 注入到字段或JavaBean属性的普通结果--> 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 <!-- <mapper>是根元素,包括一个属性namespace表示命名空间,通常会设置成“包名+SQL映射文件名”的形式 --> 6 <mapper namespace="com.itheima.mapper.UserMapper"> 7 8 <!-- <resultMap>元素表示结果映射集 9 type:resultMap最终映射的java对象类型,可以使用别名 10 id:对resultMap的唯一标识 11 --> 12 <resultMap type="com.itheima.po.User" id="resultMapID"> 13 14 <!-- 15 <id>元素表示查询结果集中唯一标识; 16 <result>元素: 17 column属性:查询出来的列名(对应数据表t_user的列名); 18 property:type实行的pojo类型中的属性名 19 最终column和property作一个映射关系 20 --> 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 <!-- <select>元素的resultMap属性表示引用上面定义的resultMapID --> 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 List<User> list = 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属性名之间做一个映射关系。