1. Jdbc演化到mybatis
1.1 jdbc开发程序
1. package cn.itcast.jdbc.test;
2. import java.sql.Connection;
3. import java.sql.DriverManager;
4. importjava.sql.PreparedStatement;
5. import java.sql.ResultSet;
6. import java.sql.SQLException;
7.
8. public class JDBCTest {
9.
10. public static void main(String[] args) {
11. Connection connection = null;
12. PreparedStatementpreparedStatement = null;
13. ResultSet resultSet =null;
14. try {
15. //加载数据库驱动
16. Class.forName("com.mysql.jdbc.Driver");
17.
18. //通过驱动管理类获取数据库链接
19. connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis01?characterEncoding=utf-8","root","admin");
20. //定义sql语句 ?表示占位符
21. String sql = "select * from user where username = ?";
22. //获取预处理statement
23. preparedStatement =connection.prepareStatement(sql);
24. //设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
25. preparedStatement.setString(1,"王五");
26. //向数据库发出sql执行查询,查询出结果集
27. resultSet = preparedStatement.executeQuery();
28. //遍历查询结果集
29. while(resultSet.next()){
30. System.out.println(resultSet.getString("id")+" "+resultSet.getString("username"));
31. }
32. } catch (Exception e) {
33. e.printStackTrace();
34. }finally{
35. //释放资源
36. if(resultSet!=null){
37. try {
38. resultSet.close();
39. } catch (SQLException e) {
40. // TODO Auto-generated catch block
41. e.printStackTrace();
42. }
43. }
44. if(preparedStatement!=null){
45. try {
46. preparedStatement.close();
47. } catch (SQLException e) {
48. // TODO Auto-generated catch block
49. e.printStackTrace();
50. }
51. }
52. if(connection!=null){
53. try {
54. connection.close();
55. } catch (SQLException e) {
56. // TODO Auto-generated catch block
57. e.printStackTrace();
58. }
59. }
60.
61. }
62.
63. }
64.
65.
66. }
1.2 Mybatis优化
1.2.1 第一步优化:连接获取和释放
问题描述:
数据库连接频繁的开启和关闭本身就造成了资源的浪费,影响系统的性能。
解决问题:
数据库连接的获取和关闭我们可以使用数据库连接池来解决资源浪费的问题。通过连接池就可以反复利用已经建立的连接去访问数据库了。减少连接的开启和关闭的时间。
问题描述:
但是现在连接池多种多样,可能存在变化,有可能采用DBCP的连接池,也有可能采用容器本身的JNDI数据库连接池。
解决问题:
我们可以通过DataSource进行隔离解耦,我们统一从DataSource里面获取数据库连接,DataSource具体由DBCP实现还是由容器的JNDI实现都可以,所以我们将DataSource的具体实现通过让用户配置来应对变化。
1.2.2 第二步优化:SQL统一存取
问题描述:
我们使用JDBC进行操作数据库时,SQL语句基本都散落在各个JAVA类中,这样有三个不足之处:
第一,可读性很差,不利于维护以及做性能调优。
第二,改动Java代码需要重新编译、打包部署。
第三,不利于取出SQL在数据库客户端执行(取出后还得删掉中间的Java代码,编写好的SQL语句写好后还得通过+号在Java进行拼凑)。
解决问题:
我们可以考虑不把SQL语句写到Java代码中,那么把SQL语句放到哪里呢?首先需要有一个统一存放的地方,我们可以将这些SQL语句统一集中放到配置文件或者数据库里面(以key-value的格式存放)。然后通过SQL语句的key值去获取对应的SQL语句。
既然我们将SQL语句都统一放在配置文件或者数据库中,那么这里就涉及一个SQL语句的加载问题。
1.2.3 第三步优化:传入参数映射和动态SQL
问题描述:
很多情况下,我们都可以通过在SQL语句中设置占位符来达到使用传入参数的目的,这种方式本身就有一定局限性,它是按照一定顺序传入参数的,要与占位符一一匹配。但是,如果我们传入的参数是不确定的(比如列表查询,根据用户填写的查询条件不同,传入查询的参数也是不同的,有时是一个参数、有时可能是三个参数),那么我们就得在后台代码中自己根据请求的传入参数去拼凑相应的SQL语句,这样的话还是避免不了在Java代码里面写SQL语句的命运。既然我们已经把SQL语句统一存放在配置文件或者数据库中了,怎么做到能够根据前台传入参数的不同,动态生成对应的SQL语句呢?
1.2.4 第四步优化:结果映射和结果缓存
问题描述:
执行SQL语句、获取执行结果、对执行结果进行转换处理、释放相关资源是一整套下来的。假如是执行查询语句,那么执行SQL语句后,返回的是一个ResultSet结果集,这个时候我们就需要将ResultSet对象的数据取出来,不然等到释放资源时就取不到这些结果信息了。我们从前面的优化来看,以及将获取连接、设置传入参数、执行SQL语句、释放资源这些都封装起来了,只剩下结果处理这块还没有进行封装,如果能封装起来,每个数据库操作都不用自己写那么一大堆Java代码,直接调用一个封装的方法就可以搞定了。
解决问题:
我们分析一下,一般对执行结果的有哪些处理,有可能将结果不做任何处理就直接返回,也有可能将结果转换成一个JavaBean对象返回、一个Map返回、一个List返回等等,结果处理可能是多种多样的。从这里看,我们必须告诉SQL处理器两点:第一,需要返回什么类型的对象;第二,需要返回的对象的数据结构怎么跟执行的结果映射,这样才能将具体的值copy到对应的数据结构上。
接下来,我们可以进而考虑对SQL执行结果的缓存来提升性能。缓存数据都是key-value的格式,那么这个key怎么来呢?怎么保证唯一呢?即使同一条SQL语句几次访问的过程中由于传入参数的不同,得到的执行SQL语句也是不同的。那么缓存起来的时候是多对。但是SQL语句和传入参数两部分合起来可以作为数据缓存的key值。
1.2.5 第五步优化:解决重复SQL语句问题
问题描述:
由于我们将所有SQL语句都放到配置文件中,这个时候会遇到一个SQL重复的问题,几个功能的SQL语句其实都差不多,有些可能是SELECT后面那段不同、有些可能是WHERE语句不同。有时候表结构改了,那么我们就需要改多个地方,不利于维护。
解决问题:
当我们的代码程序出现重复代码时怎么办?将重复的代码抽离出来成为独立的一个类,然后在各个需要使用的地方进行引用。对于SQL重复的问题,我们也可以采用这种方式,通过将SQL片段模块化,将重复的SQL片段独立成一个SQL块,然后在各个SQL语句引用重复的SQL块,这样需要修改时只需要修改一处即可。
优化总结:
我们总结一下上面对JDBC的优化和封装:
(1)使用数据库连接池对连接进行管理
(2) SQL语句统一存放到配置文件
(3) SQL语句变量和传入参数的映射以及动态SQL
(4)动态SQL语句的处理
(5)对数据库操作结果的映射和结果缓存
SQL语句的重复
2. mybatis简介
2.1 Mybatis是什么?
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回
Mybatis是apache旗下的顶级一个项目,mybatis是对jdbc的封装的一个持久层框架
对比hibernate.cfg.xml:hibernate基础环境配置文件—连接关联(数据源),事务管理。
基础支撑层:
Mybatis:sqlMapConfig.xml(全局配置文件)
1) 数据源
2) 事务
1.1.1.2. 3)加载映射文件
数据处理层:
1) Mybatis接受参数进行增加,删除,修改,查询,进行结构集映射。
接口层:
1.1.1.3. 1)程序员可以调用接口一些方法,实现增加,删除,修改,查询(SqlSession)
1.1.1.4.
mybatis的配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
l 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
l 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
l mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
l Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
l Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
3. mybatis入门程序
3.1 需求
根据用户ID(主键)进行查询用户信息
根据用户名称模糊查询用户信息
添加用户
删除用户
更新用户
3.2 环境
Java环境:jdk1.7.0_72
Eclipse:kepler
Mysql:5.5
mybaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases
mybatis-3.2.7.jar----mybatis的核心包
lib----mybatis的依赖包
mybatis-3.2.7.pdf----mybatis使用手册
3.3 创建mysql数据库
先导入sql_table.sql,再导入 sql_data.sql脚本:
如下:
3.4 mybatis入门程序
3.4.1 环境准备
3.4.1.1 创建一个Java工程
3.4.1.2 4.1.2.导入jar文件
3.4.1.3 log4j日志
3.4.1.4 4.1.4.创建sqlMapConfig.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEconfiguration
PUBLIC "-//mybatis.org//DTDConfig 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 初始化环境,和spring整合以后,这个将会被废除 -->
<environmentsdefault="development">
<environmentid="development">
<!-- 使用jdbc管理事务,事务控制是由mybatis来执行 -->
<transactionManagertype="JDBC"/>
<!-- 数据源也是由mybatis来进行管理-->
<dataSourcetype="POOLED">
<propertyname="driver"value="com.mysql.jdbc.Driver"/>
<propertyname="url"value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
<propertyname="username"value="root"/>
<propertyname="password"value="admin"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 引入映射文件 -->
<!-- <mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
</mappers>
</configuration>
sqlMapConfig是mybatis的核心配置文件,包含数据源,事务管理等等
3.4.1.5 4.1.5.创建PO类
3.4.2.1 准备Mapper映射文件
在classpath下sqlMap里面创建映射文件User.xml(此名称可以任意定义)
测试开发:定义映射文件user.xml
User.xml内容语法:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace是命名空间,用来隔离sql语句,可以随意定义,
注意:在使用代理时具有特殊的约定含义,不能随意定义 -->
<mappernamespace="test">
</mapper>
Namespace:命名空间用来隔离sql语句,在mybatis代理模式具有特殊的含义
详细的mapper文件如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace是命名空间,用来隔离sql语句,可以随意定义,
注意:在使用代理时具有特殊的约定含义,不能随意定义 -->
<mappernamespace="test">
<!-- 首先明确:mybatis的所有sql语句都存放在xml的映射文件中,也就是说有多个sql -->
<!-- id:id就是我们唯一标识一个sql语句的地址
mybatis会将sql语句封装到mappedStatement对象中,id就是statement的id
注意:我们需要根据ID进行查询,需要接受参数使用parameterType进行接受参数
#,$都用来接受参数,就是占位符接受参数,注意:如果传递的是基本类型的参数,#{??}里面可以任意
parameterType:传递参数
resultType:结果集映射 -->
<selectid="selectUserByID"parameterType="int"resultType="cn.itcast.bean.User">
select * from user where id=#{id}
</select>
</mapper>
3.4.2.2 ID查询测试类
测试代码:
public class MybatisTest {
private SqlSessionFactorysessionFactory;
@Before
public voidcreateSessionFactory() throws Exception{
String res="sqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(res);
sessionFactory = newSqlSessionFactoryBuilder().build(inputStream);
}
@Test
public voidtest02(){
//获取Session
SqlSession session = sessionFactory.openSession();
User user = session.selectOne("test.selectUserByID",1);
System.out.println(user);
session.close();
}
@Test
public voidtest01() throwsException{
String resources="sqlMapConfig.xml";
//读取文件资源流
InputStream inputStream = Resources.getResourceAsStream(resources);
//创建一个SessionFactory
SqlSessionFactory sessionFactory = newSqlSessionFactoryBuilder().build(inputStream);
//获取Session
SqlSession session = sessionFactory.openSession();
User user = session.selectOne("test.selectUserByID",1);
System.out.println(user);
session.close();
}
}
3.4.3 根据姓名username模糊查询
3.4.3.1 映射文件
<!--需求:根据用户姓名进行模糊查询,可能返回多条记录
resultType:指定返回单条记录,映射成Java单个对象
${}拼接sql语句,对参数不加任何修饰的拼接在sql语句中
${value}:如果传入的参数类型是基本类型,那么${}内只能是value -->
<selectid="selectUserByUsername"parameterType="string"resultType="cn.itcast.bean.User">
select * from user where username like '%${value}%'
</select>
3.4.3.2 测试代码模糊查询
@Test
public voidselectUserByUsername(){
SqlSession session = sessionFactory.openSession();
//第一个参数:statement的id,根据id找到需要执行的sql
//第二个参数:指定匹配parameterType的参数类型
List<User> list =session.selectList("test.selectUserByUsername","张");
System.out.println(list);
}
3.4.4 #,$
#{}表示一个占位符,通过#{}可以实现preparedStatement向占位符中设置值,自动进行Java
类型和jdbc类型转换,#{}可以有效防止sql注入。#{}可以接受简单类型值或pojo属性值。
如果parameterType传输单个类型的值,#{}括号中可以是value或者其他任意值。
${}表示拼接sql串,通过${}可以通过patameterType传入的内容拼接在sql中且不进行jdbc类型转换。${}可以接受简单类型值或pojo属性值,如果parameterType传输单个类型值,${}括号中只能是value.
3.4.5 parameterType和resultType
patameterType:指定传递参数类型,mybatis通过ognl获取参数拼接在sql语句中
resultType:指定返回结果类型,mybatis可以把查询结果封装成Java对象,这里就是把结果集映射成resultType指定的对象。
3.4.6 selectOne和selectList
selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned byselectOne(), but found: 3
atorg.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)
selectList可以查询一条或多条记录。
3.5 添加
3.5.1 映射文件(user.xml)
<!-- parameterType:指定输入参数类型pojo,就是javabean对象
#{}口号中是Javabean的属性名,mybatis通过ognl来获取javabean的属性值 -->
<insertid="insertUser"parameterType="cn.itcast.bean.User">
<!--使用sql函数生成主键ID注意:mysql主键是在执行完成insert语句后才增加主键,所以使用after -->
<selectKeykeyProperty="id"order="AFTER"resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(id,username,birthday,sex,address)
values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
Mysql自增主键返回:
selectKey实现自增主键返回:
keyProperty:返回值对应pojo里面的那个属性。
Order:表示id生成的顺序,由于mysql主键生成是在sql语句执行之后在进行设置,所以我们设置成after。
ResultType:主键返回类型
LAST_INSERT_ID()是mysql函数,返回auto_increament自增id值
也可以使用useGeneratedKeys来返回主键
3.5.2 添加测试代码
@Test
public void test01() throws Exception{
SqlSession sqlSession =sessionFactory.openSession();
User user = new User();
user.setUsername("张三");
user.setSex("男");
user.setBirthday(new Date());
user.setAddress("陕西");
sqlSession.insert("test.insertUser", user);
System.out.print(user.getId);//使用last_insert_Id返回ID
sqlSession.commit();
sqlSession.close();
}
3.5.3 mysql使用uuid实现主键自增
注意:mysql的uuid生成必须在执行insert之前进行,因为后面需要获取uuid的属性值进行表的插入。
3.5.4 oracle的自增序列
Oracle序列的自定义方法:
注意:oracle自增主键是序列化自增类型。需要before
3.6 删除
3.6.1 映射文件
3.6.2 删除测试
@Test
public voiddeleteUserByID(){
SqlSession session = sessionFactory.openSession();
//删除单表,没有外键关联才能被删除
session.delete("test.deleteUserByID", 32);
session.commit();
session.close();
}
3.7 修改
3.7.1 映射文件
3.7.2 修改测试
3.7.3 测试结果
3.8 总结
3.8.1 parameterType
指定传递参数类型,前台传入参数和后台获取参数类型必须匹配
3.8.2 resultType
指定返回值类型,执行sql结果映射Java对象
3.8.3 #和$
#{}表示一个占位符,#{}接受传入参数,类型可以是基本类型,pojo,map
如果接受的是基本类型的值,那么#{}括号中可以任意或者value
如果#{}获取是的pojo,mybatis通过ognl获取参数值。Ognl就是对象导航语言属性.属性.属性的方式获取值。
如果传递是map值,#{}中需要的是map的key
${}表示拼接sql,会引入sql注入,不建议使用
${}接受输入参数可以是pojo,基本类型,map
${}如果接受的是基本类型,只能是value
${}接受pojo类型的参数,通过ognl对象导航进行获取
4. mybatis的dao开发
4.1 sqlSessionFactoryBuider
SqlSessionFactoryBuidler如果和spring进行整合,必须是单列,现在测试,把sqlSesioinFactoryBuidler当成一个工具类。来创建sqlSessionFactory
4.2 sqlSessionFactory
SqlSessionFactory是单列,用来生成sqlSesion,在这里测试,sqlsessionFactory当成一个工具类使用就ok。
4.3 sqlSession
SqlSession是mybatis提供的接口,接口里面有很多操作数据库方法,我们只需要调用sqlsession里面方法。回话:sqlSession用来搬运数据,搬运数据到数据库
SqlSession和hibernate的Session:一级缓存
sessionFactory级别的二级缓存。Mybatis二级缓存的存储区域:根据Mapper映射文件来开辟存储空间。有多个namespace,就有多少二级缓存的存储空间。
4.4 原始Dao开发方式
原始Dao开发方法需要程序员编写Dao接口和Dao实现类。
4.4.1 映射文件
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="test">
<!--根据id获取用户信息 -->
<select id="findUserById"parameterType="int"resultType="cn.itcast.mybatis.po.User">
select * from user where id = #{id}
</select>
<!--添加用户 -->
<insert id="insertUser"parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id"order="AFTER"resultType="java.lang.Integer">
selectLAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
4.4.2 Dao接口
Public interface UserDao {
public User getUserById(int id)throws Exception;
public void insertUser(User user)throws Exception;
}
Public class UserDaoImplimplements UserDao {
//注入SqlSessionFactory
publicUserDaoImpl(SqlSessionFactory sqlSessionFactory){
this.setSqlSessionFactory(sqlSessionFactory);
}
private SqlSessionFactorysqlSessionFactory;
@Override
public UsergetUserById(int id)throws Exception {
SqlSession session = sqlSessionFactory.openSession();
User user = null;
try {
//通过sqlsession调用selectOne方法获取一条结果集
//参数1:指定定义的statement的id,参数2:指定向statement中传递的参数
user = session.selectOne("test.findUserById", 1);
System.out.println(user);
} finally{
session.close();
}
return user;
}
@Override
Public void insertUser(User user)throws Exception {
SqlSession sqlSession =sqlSessionFactory.openSession();
try {
sqlSession.insert("insertUser", user);
sqlSession.commit();
} finally{
session.close();
}
}
}
4.4.3 Dao测试
创建一个JUnit的测试类,对UserDao进行测试。
private SqlSessionFactorysqlSessionFactory;
@Before public void init() throws Exception { SqlSessionFactoryBuilder sessionFactoryBuilder =new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); sqlSessionFactory =sessionFactoryBuilder.build(inputStream); }
@Test public void testGetUserById() { UserDao userDao = new UserDaoImpl(sqlSessionFactory); User user = userDao.getUserById(22); System.out.println(user); } } |
4.4.4 问题
开发中存在以下问题:
u Dao方法体存在重复代码:通过SqlSessionFactory创建,调用SqlSession的数据库操作方法
u 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不便于维护。
4.5 Mapper动态代理方式
4.5.1 开发规范
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
1、 Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
4.5.2 Mapper.xml(映射文件)
定义mapper映射文件UserMapper.xml(内容同Users.xml),需要修改namespace的值为 UserMapper接口路径。将UserMapper.xml放在classpath 下mapper目录下:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="cn.itcast.mybatis.mapper.UserMapper">
<!--根据id获取用户信息 -->
<select id="findUserById"parameterType="int"resultType="cn.itcast.mybatis.po.User">
select * from user where id =#{id}
</select>
<!--自定义条件查询用户列表 -->
<select id="findUserByUsername"parameterType="java.lang.String"
resultType="cn.itcast.mybatis.po.User">
select * from user whereusername like '%${value}%'
</select>
<!--添加用户 -->
<insert id="insertUser"parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER"resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
4.5.3 Mapper.java(接口文件)
/**
*用户管理mapper
*/
Public interface UserMapper {
//根据用户id查询用户信息
public User findUserById(int id)throws Exception;
//查询用户列表
public List<User>findUserByUsername(String username)throws Exception;
//添加用户信息
publicvoid insertUser(Useruser)throws Exception;
}
接口定义有如下特点:
1、 Mapper接口方法名和Mapper.xml中定义的statement的id相同
2、 Mapper接口方法的输入参数类型和mapper.xml中定义的statement的parameterType的类型相同
3、 Mapper接口方法的输出参数类型和mapper.xml中定义的statement的resultType的类型相同
4.5.4 加载UserMapper.xml文件
修改SqlMapConfig.xml文件:
<!-- 加载映射文件 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
4.5.5 测试
Public class UserMapperTestextends TestCase {
private SqlSessionFactorysqlSessionFactory;
protected void setUp()throws Exception {
//mybatis配置文件
String resource = "sqlMapConfig.xml";
InputStream inputStream =Resources.getResourceAsStream(resource);
//使用SqlSessionFactoryBuilder创建sessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
Public void testFindUserById()throws Exception {
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获取mapper接口的代理对象
UserMapper userMapper =session.getMapper(UserMapper.class);
//调用代理对象方法
User user =userMapper.findUserById(1);
System.out.println(user);
//关闭session
session.close();
}
@Test
publicvoidtestFindUserByUsername()throws Exception {
SqlSession sqlSession =sqlSessionFactory.openSession();
UserMapper userMapper =sqlSession.getMapper(UserMapper.class);
List<User> list =userMapper.findUserByUsername("张");
System.out.println(list.size());
}
Public void testInsertUser()throws Exception {
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获取mapper接口的代理对象
UserMapper userMapper =session.getMapper(UserMapper.class);
//要添加的数据
User user = new User();
user.setUsername("张三");
user.setBirthday(new Date());
user.setSex("1");
user.setAddress("北京市");
//通过mapper接口添加用户
userMapper.insertUser(user);
//提交
session.commit();
//关闭session
session.close();
}
}
4.5.6 小结
u selectOne和selectList
动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
u namespace
mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。
4.6 mybatis和hibernate
Mybatis和hibernate都是对jdbc封装:
Hibernate优点:
完全面向对象,不需要我们自己写sql语句
数据库迁移,hibernate使用面向对象开发,只需要修改方言
Hibernate缺点:
Hibernate维护关系对我们是透明的,维护关系比较复杂,性能调优也是比较复杂。
Hibernate:把Hql变成sql语句再进行执行。速度变慢
Hibernate:mysql生成sql语句不规范,不易挑错。
Hibernate:由于使用面向对象开发,不能开发复杂业务。
使用与需求变化比较少的项目:CRM,ERP
Mybatis:mybatis简化程序员的工作,把精力放在sql语句上面。适合开发复杂业务。对项目维护,调优比较容易。尤其是需求变化特别快的项目都采用mybatis来开发(互联网项目)
5. sqlMapConfig
5.1 配置内容
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
5.2 Properties
引入资源文件:引入数据资源文件
5.3 settings
配置mybatis全局参数:开启一级缓存 开启二级缓存
5.4 typeAliases(别名)
5.4.1 定义单个别名
5.4.1.1 sqlMapConfig
5.4.1.2 修改映射文件
5.4.2 批量定义别名
5.4.2.1 使用package批量定义别名
使用package定义的别名:就是pojo的类名,大小写都可以。
映射文件
5.5 typeHandlers
通常mybatis的typeHandlers完成jdbc类型和Java类型的转换
通常情况下,mybatis提供的类型处理器满足日常的需求,不需要自定义
mybatis支持类型处理器:
类型处理器 | Java类型 | JDBC类型 |
BooleanTypeHandler | Boolean,boolean | 任何兼容的布尔值 |
ByteTypeHandler | Byte,byte | 任何兼容的数字或字节类型 |
ShortTypeHandler | Short,short | 任何兼容的数字或短整型 |
IntegerTypeHandler | Integer,int | 任何兼容的数字和整型 |
LongTypeHandler | Long,long | 任何兼容的数字或长整型 |
FloatTypeHandler | Float,float | 任何兼容的数字或单精度浮点型 |
DoubleTypeHandler | Double,double | 任何兼容的数字或双精度浮点型 |
BigDecimalTypeHandler | BigDecimal | 任何兼容的数字或十进制小数类型 |
StringTypeHandler | String | CHAR和VARCHAR类型 |
ClobTypeHandler | String | CLOB和LONGVARCHAR类型 |
NStringTypeHandler | String | NVARCHAR和NCHAR类型 |
NClobTypeHandler | String | NCLOB类型 |
ByteArrayTypeHandler | byte[] | 任何兼容的字节流类型 |
BlobTypeHandler | byte[] | BLOB和LONGVARBINARY类型 |
DateTypeHandler | Date(java.util) | TIMESTAMP类型 |
DateOnlyTypeHandler | Date(java.util) | DATE类型 |
TimeOnlyTypeHandler | Date(java.util) | TIME类型 |
SqlTimestampTypeHandler | Timestamp(java.sql) | TIMESTAMP类型 |
SqlDateTypeHandler | Date(java.sql) | DATE类型 |
SqlTimeTypeHandler | Time(java.sql) | TIME类型 |
ObjectTypeHandler | 任意 | 其他或未指定类型 |
EnumTypeHandler | Enumeration类型 | VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。 |
5.6 mappers
5.6.1 引入映射文件
5.6.2 扫描接口(代理开发模式)
* 接口方法必须和Mapper映射文件Statement的ID一致
* namespace的名称必须是接口的全类路径名
* 返回值类型必须和Statement的返回值类型一致
* 输入映射参数必须和parameterType输入参数一致
* 接口和映射文件必须在同一个目录
* 接口类名必须Mapper映射文件名称相同
5.6.2.1 配置单个接口
映射文件:
接口:
5.6.2.2 批量扫描接口
映射文件同上:
测试代码同上