Mybatis入门---dao开发和mapper代理开发
Posted mvcq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis入门---dao开发和mapper代理开发相关的知识,希望对你有一定的参考价值。
在说mabatis之前,先说说单独使用jdbc编程的缺陷。
jdbc编程的大概流程大家都很清楚,基本分为以下几步:
- 加载数据驱动
- 创建并获取数据库连接
- 创建jdbc statement对象
- 设置sql语句,并设置sql语句中的参数
- 通过statement执行sql并获取结果
- 对执行的结果进行解析处理
- 释放资源
1 public static void main(String[] args) { 2 Connection connection = null; 3 PreparedStatement preparedStatement = null; 4 ResultSet resultSet = null; 5 6 try { 7 //加载数据库驱动 8 Class.forName("com.mysql.jdbc.Driver"); 9 // 通过驱动管理类获取数据库链接 10 connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mysql"); 11 // 定义sql语句 ?表示占位符 12 String sql = "select * from user where username = ?"; 13 // 获取预处理statement 14 preparedStatement = connection.prepareStatement(sql); 15 // 设置参数 16 preparedStatement.setString(1, "王五"); 17 // 向数据库发出sql执行查询,查询出结果集 18 resultSet = preparedStatement.executeQuery(); 19 // 遍历查询结果集 20 while(resultSet.next()){ 21 System.out.println(resultSet.getString("id")+" "+resultSet.getString("username")); 22 } 23 } catch (Exception e) { 24 e.printStackTrace(); 25 }finally{ 26 if(resultSet!=null){ 27 try { 28 resultSet.close(); 29 } catch (SQLException e) { 30 e.printStackTrace(); 31 } 32 } 33 if(preparedStatement!=null){ 34 try { 35 preparedStatement.close(); 36 } catch (SQLException e) { 37 e.printStackTrace(); 38 } 39 } 40 if(connection!=null){ 41 try { 42 connection.close(); 43 } catch (SQLException e) { 44 e.printStackTrace(); 45 } 46 } 47 48 } 49 50 }
问题总结如下:
1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能。
2、 Sql语句在代码中硬编码(参数写死),造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
3、 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
4、 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
由于这些问题的存在,mybatis对其进行了相应的处理:
1、在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
2、将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4、Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。
它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
mybatis框架基本内容
1. mybatis架构图如下
2. mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
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的dao开发必备的内容
3.1 mybatis核心包、依赖包、数据驱动包。
3.2 日志配置文件
3.3 SqlMapConfig.xml(名字随意)作为全局配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <configuration> 6 <properties resource="jdbc.properties"></properties> 7 <environments default="development"> 8 <environment id="development"> 9 <transactionManager type="JDBC" /> 10 <dataSource type="POOLED"> 11 <property name="driver" value="${jdbc.driver}" /> 12 <property name="url" value="${jdbc.url}" /> 13 <property name="username" value="${jdbc.user}" /> 14 <property name="password" value="${jdbc.password}" /> 15 </dataSource> 16 </environment> 17 </environments> 18 <mappers> 19 <mapper resource="sqlMap/UserMapper.xml"/> 20 </mappers> 21 </configuration>
3.4 pojo类
1 public class User { 2 3 private int id; 4 private String username; 5 private String address; 6 private Date birthday; 7 }
3.5 映射文件(需要在全局配置文件SqlMapConfgi.xml进行加载,mappers的内容)
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="test"> 6 <!-- 根据id获取用户信息 --> 7 <select id="findUserById" parameterType="int" resultType="priv.cq.mybatis.po.User"> 8 select * from user where id=#{id} 9 </select> 10 </mapper>
3.6 Dao接口
1 public interface IUserDao { 2 // 根据用户id查询用户 3 public User findUserById(int id) throws Exception; 4 }
3.7 Dao接口实现类
1 public class UserDaoImpl implements IUserDao{ 2 3 private SqlSessionFactory sqlSessionFactory; 4 5 public UserDaoImpl(SqlSessionFactory sqlSessionFactory) { 6 this.sqlSessionFactory = sqlSessionFactory; 7 } 8 @Override 9 public User findUserById(int id) throws Exception { 10 SqlSession session = sqlSessionFactory.openSession(); 11 User user = session.selectOne("test.findUserById", id); 12 session.close(); 13 return user; 14 } 15 }
3.8 测试
1 public class IUserDaoTest { 2 private SqlSessionFactory sqlSessionFactory; 3 4 @Before 5 public void setUp() throws Exception { 6 String resource = "SqlMapConfig.xml"; 7 InputStream inputStream = Resources.getResourceAsStream(resource); 8 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 9 } 10 11 @Test 12 public void testFindUserById() throws Exception { 13 IUserDao userDao = new UserDaoImpl(sqlSessionFactory); 14 User user = userDao.findUserById(32); 15 System.out.println(user); 16 } 17 }
注意的地方:
1. SqlSession
SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。同时SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作,默认使用DefaultSqlSession实现类。
执行过程如下:
1) 加载数据源等配置信息(Environment environment = configuration.getEnvironment();)
2) 创建数据库链接
3)创建事务对象
4)创建Executor,SqlSession所有操作都是通过Executor完成,mybatis源码如下:
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
2. sqlSessionFactory
SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。
3. sqlSessionFactoryBuilder
sqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
Dao接口存在的不足之处:
1. Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
本例中只有一个方法,如果有各种查询、删除、查找等方法,将会存在上述的冗余。
2. 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。
4. mybatis的mapper动态代理开发
4.1 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的类型相同
1 public interface UserMapper { 2 // 根据用户id查询用户 3 public User findUserById(int id) throws Exception; 4 // 根据用户姓名模糊查询用户 5 public List<User> findUserByName(String name) throws Exception; 6 // 插入用户 7 public void insertUser(User user) throws Exception; 8 // 删除用户 9 public void deleteUser(int i) throws Exception; 10 // 更新用户 11 public void updateUser(User user) throws Exception; 12 }
4.2 映射文件 mapper.xml
定义mapper映射文件UserMapper.xml,需要修改namespace的值为 UserMapper接口路径。将UserMapper.xml放在classpath 下mapper目录下。
1 <mapper namespace="priv.cq.mybatis.mapper.UserMapper"> 2 <select id="findUserById" parameterType="int" resultType="user"> 3 select * from user where id=#{id} 4 </select> 5 6 <select id="findUserByName" parameterType="java.lang.String" resultType="user"> 7 select * from user where username like ‘%${value}%‘ 8 </select> 9 10 <insert id="insertUser" parameterType="user"> 11 <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> 12 select LAST_INSERT_ID() 13 </selectKey> 14 insert into user(username,birthday,address)value(#{username},#{birthday},#{address}) 15 </insert> 16 17 <delete id="deleteUser" parameterType="int"> 18 delete from user where id=#{id} 19 </delete> 20 21 <update id="updateUser" parameterType="user"> 22 update user set username=#{username},birthday=#{birthday},address=#{address} where id=#{id} 23 </update> 24 </mapper>
4.3 修改SqlMapConfig.xml文件
1 <mappers> 2 <mapper resource="mapper/UserMapper.xml"/> 3 </mappers>
4.4 测试
1 public class IUserMapperTest { 2 3 private SqlSessionFactory sqlSessionFactory; 4 5 @Before 6 public void setUp() throws Exception { 7 String resource = "SqlMapConfig.xml"; 8 InputStream inputStream = Resources.getResourceAsStream(resource); 9 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 10 } 11 12 // 根据id查找用户 13 @Test 14 public void testFindUserById() throws Exception { 15 // 获取session 16 SqlSession sqlSession = sqlSessionFactory.openSession(); 17 // 获取mapper接口的代理对象 18 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 19 // 调用代理对象方法 20 User user = userMapper.findUserById(1); 21 System.out.println(user); 22 // 关闭sqlSession 23 sqlSession.close(); 24 } 25 26 // 根据用户姓名模糊查询用户 27 @Test 28 public void testFindUserByName() throws Exception { 29 SqlSession sqlSession = sqlSessionFactory.openSession(); 30 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 31 List<User> list = userMapper.findUserByName("曹乾"); 32 System.out.println(list); 33 sqlSession.close(); 34 } 35 36 // 插入用户 37 @Test 38 public void testInsertUser() throws Exception { 39 SqlSession sqlSession = sqlSessionFactory.openSession(); 40 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 41 42 User user = new User(); 43 user.setUsername("小王"); 44 user.setBirthday(new Date()); 45 user.setAddress("北京"); 46 47 userMapper.insertUser(user); 48 sqlSession.commit(); 49 sqlSession.close(); 50 } 51 52 // 根据id删除用户 53 @Test 54 public void testDeleteUser() throws Exception { 55 SqlSession sqlSession = sqlSessionFactory.openSession(); 56 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 57 userMapper.deleteUser(39); 58 sqlSession.commit(); 59 sqlSession.close(); 60 } 61 62 // 根据id更新用户(此id必须存在) 63 @Test 64 public void testUpdateUser() throws Exception { 65 SqlSession sqlSession = sqlSessionFactory.openSession(); 66 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 67 68 User user = new User(); 69 user.setId(31); 70 user.setAddress("孙悟空"); 71 user.setBirthday(new Date()); 72 user.setUsername("花果山"); 73 74 userMapper.updateUser(user); 75 sqlSession.commit(); 76 sqlSession.close(); 77 } 78 }
mapper动态代理中,动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
工程结构如下:
两种开发方法就简单地介绍到此,只是一个简单的demo,但大体流程已经很清楚了,在下次将把mybatis更高级的内容做一整理,比如mybatis的高级映射、缓存以及和spring的整合。
以上是关于Mybatis入门---dao开发和mapper代理开发的主要内容,如果未能解决你的问题,请参考以下文章