MyBatis02
MyBatis解决JDBC编程的问题:
1.数据库连接创建,释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可以解决此问题。
解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库连接。
2.Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变Java代码。
解决:将sql语句配置在XXXXmapper.xml文件中与Java代码分离。
3.向sql语句传参麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4.对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
Mybaits和Hibernate不同
mybatis和hibernate不同,他不完全是一个orm框架,因为mybatis需要程序员自己编写sql语句。mybaits可以通过XML注解方式灵活配置要运行的sql语句,并将Java对象和sql语句映射生成最终执行sql,最后将slq执行的结果再映射生成Java对象。
Mybaits学习门槛低,简单易学,程序员直接编写原生态Sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件,企业运营类软件等,因为这类软件需求变化频繁,一一旦需求变化成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码 ,提高效率。但是hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好hibernate需要具备很强的经验和能力才行。
总之,按照用户的需求在有限的资源环境下只要能做出维护性,拓展性良好的软件架构都是好架构,所有框架只有适合才是最好。
原始Dao开发:
原始Dao开发方法需要编写Dao接口和DaoImpl的实现层
1.映射文件
编写映射文件如下:
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 <!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 --> 6 <mapper namespace="test"> 7 <!-- id:statement的id 或者叫做sql的id --> 8 <!-- parameterType:声明输入参数的类型 --> 9 <!-- resultType:声明输出结果的类型,应该填写pojo的全路径 --> 10 <!-- #{}:输入参数的占位符,相当于jdbc的? --> 11 <select id="findUserById" parameterType="integer" resultType="com.test.bean.User"> 12 select * from user where id =#{id} 13 </select> 14 <select id="queryUserByUsername" parameterType="String" resultType="com.test.bean.User"> 15 SELECT * FROM user WHERE username LIKE #{username} 16 </select> 17 <!-- 如果传入的参数是简单数据类型,${}里面必须写value --> 18 <select id="queryUserByUsername2" parameterType="string" 19 resultType="com.test.bean.User"> 20 SELECT * FROM user WHERE username LIKE '%${value}%' 21 </select> 22 <!-- 插入数据 --> 23 <insert id="saveUser" parameterType="com.test.bean.User"> 24 <!-- selectKey 标签实现主键返回 --> 25 <!-- keyColumn:主键对应的表中的哪一列 --> 26 <!-- keyProperty:主键对应的pojo中的哪一个属性 --> 27 <!-- order:设置在执行insert语句前执行查询id的sql,孩纸在执行insert语句之后执行查询id的sql --> 28 <!-- resultType:设置返回的id的类型 --> 29 <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int"> 30 SELECT LAST_INSERT_ID() 31 </selectKey> 32 INSERT INTO user VALUES (null,#{username},#{birthday},#{sex},#{address}) 33 </insert> 34 <!-- 修改用户名 --> 35 <update id="updateUserById" parameterType="com.test.bean.User"> 36 UPDATE user SET username = #{username} WHERE id = #{id} 37 </update> 38 <!-- 删除用户 --> 39 <delete id="deleteUserById" parameterType="int"> 40 delete from user where id=#{id} 41 </delete> 42 </mapper>
2.Dao接口,先进行Dao接口的开发,编程如下:
1 public interface UserDao { 2 3 User findUserById(int id); 4 5 List<User> queryUserByUsername(String name); 6 7 void saveUser(User user); 8 9 }
3.Dao的实现类,如下:
1 public class UserDaoImpl implements UserDao { 2 3 private SqlSessionFactory sqlSessionFactory; 4 5 public UserDaoImpl(SqlSessionFactory sqlSessionFactory){ 6 7 this.sqlSessionFactory = sqlSessionFactory; 8 9 } 10 11 12 13 public User findUserById(int id) { 14 15 SqlSession sqlSession = this.sqlSessionFactory.openSession(); 16 17 User user = sqlSession.selectOne("findUserById", id); 18 19 sqlSession.close(); 20 21 return user; 22 23 } 24 25 26 27 public List<User> queryUserByUsername(String name) { 28 29 SqlSession sqlSession = this.sqlSessionFactory.openSession(); 30 31 List<User> list = sqlSession.selectList("queryUserByUsername", name); 32 33 sqlSession.close(); 34 35 return list; 36 37 } 38 39 40 41 public void saveUser(User user) { 42 43 SqlSession sqlSession = this.sqlSessionFactory.openSession(); 44 45 sqlSession.insert("saveUser", user); 46 47 sqlSession.commit(); 48 49 sqlSession.close(); 50 51 } 52 53 }
4.在junit进行测试:
1 public class MybatisDaoImplTest { 2 3 private SqlSessionFactory sqlSessionFactory; 4 5 6 7 @Before 8 9 public void init() throws IOException { 10 11 // 创建SqlSessionFactoryBuilder 12 13 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); 14 15 // 加载SqlMapConfig.xml文件 16 17 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); 18 19 // 创建sqlSessionFactory对象 20 21 this.sqlSessionFactory = sqlSessionFactoryBuilder.build(in); 22 23 } 24 25 26 27 @Test 28 29 public void testFindUserById() { 30 31 // 创建Dao 32 33 UserDao userdao = new UserDaoImpl(this.sqlSessionFactory); 34 35 // 执行查询 36 37 User user = userdao.findUserById(1); 38 39 System.out.println(user); 40 41 } 42 43 44 45 @Test 46 47 public void queryUserByUsername() { 48 49 // 创建Dao 50 51 UserDao userdao = new UserDaoImpl(this.sqlSessionFactory); 52 53 List<User> list = userdao.queryUserByUsername("张"); 54 55 for (User user : list) { 56 57 System.out.println(user); 58 59 } 60 61 } 62 63 @Test 64 65 public void testSaveUser(){ 66 67 UserDao userdao = new UserDaoImpl(this.sqlSessionFactory); 68 69 User user = new User(null, "刘备", new Date(), '2', "蜀国"); 70 71 userdao.saveUser(user); 72 73 System.out.println(user); 74 75 } 76 77 }
5.问题
原始的Dao开发中存在以下问题:
Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法。
调用sqlSession的数据库操作方法需要指定stament的id,这里存在硬编码,不得于开发维护。
Mapper动态代理方式开发
1.开发规范
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边的Dao接口实现类方法。
Mapper接口开发需要遵循一下规范:
1.Mapper.xml文件中的namespace与mapper接口的路径相同。
2.Mapper接口方法名和Mapper.xml中定义的每个stament的id相同。
3.Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同。
4.Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。
2.Mapper.xml(映射文件)
定义mapper映射文件UserMapper.xml.将UserMapper.xml放在config下的mapper目录下,如图 :

userMapper.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"> <!-- 使用动态代理开发Dao,namespace必须和Mapper接口路径一致 --> <mapper namespace="com.test.mapper.UserMapper"> <select id="findUserById" parameterType="integer" resultType="com.test.bean.User"> select * from user where id =#{id} </select> <select id="queryUserByUsername" parameterType="String" resultType="com.test.bean.User"> SELECT * FROM user WHERE username LIKE #{username} </select> <select id="queryUserByUsername2" parameterType="string" resultType="com.test.bean.User"> SELECT * FROM user WHERE username LIKE '%${value}%' </select> <!-- 插入数据 --> <insert id="saveUser" parameterType="com.test.bean.User"> <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO user VALUES (null,#{username},#{birthday},#{sex},#{address}) </insert> <!-- 修改用户名 --> <update id="updateUserById" parameterType="com.test.bean.User"> UPDATE user SET username = #{username} WHERE id = #{id} </update> <!-- 删除用户 --> <delete id="deleteUserById" parameterType="int"> delete from user where id=#{id} </delete> </mapper>
3.UserMapper(接口文件)
创建UserMapper接口代码如下:
1 public interface UserMapper { 2 3 //遵循四个原则 4 5 //接口 方法名 == User.xml中的id 6 7 //返回值类型 与Mapper.xml文件中返回值类型要一致 8 9 //方法的入参类型与 Mapper.xml中入参的类型要一致 10 11 //命名空间绑定接口 12 13 public User findUserById(Integer id); 14 15 public List<User> queryUserByUsername2(String name); 16 17 public void saveUser(User user); 18 19 }
4.加载UserMapper.xml文件
修改SqlMapConfig.xml文件,添加以下所示的内容:
1 <mappers> 2 3 <mapper resource="sqlmap/user.xml"/> 4 5 <mapper resource="mapper/userMapper.xml"/> 6 7 </mappers>
5.测试
编写测试方法如下:
1 public class MybatisMapperTest { 2 private SqlSessionFactory sqlSessionFactory; 3 @Before 4 public void init()throws Exception{ 5 //创建sqlSessionFactoryBuilder 6 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); 7 //加载SqlMapConfig.xml文件 8 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); 9 //创建SqlSessionFactory 10 this.sqlSessionFactory = sqlSessionFactoryBuilder.build(in); 11 } 12 @Test 13 public void testMapper() throws Exception{ 14 //创建SqlSession 15 SqlSession sqlsession = this.sqlSessionFactory.openSession(); 16 //SqlSession帮我生成一个实现类(给接口) 17 UserMapper Usermapper = sqlsession.getMapper(UserMapper.class); 18 User user = Usermapper.findUserById(10); 19 System.out.println(user); 20 sqlsession.commit(); 21 } 22 @Test 23 public void testQueryUserByUsername() { 24 // 获取sqlSession,和spring整合后由spring管理 25 SqlSession sqlSession = this.sqlSessionFactory.openSession(); 26 // 从sqlSession中获取Mapper接口的代理对象 27 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 28 // 执行查询方法 29 List<User> list = userMapper.queryUserByUsername2("王"); 30 for (User user : list) { 31 System.out.println(user); 32 } 33 sqlSession.close(); 34 } 35 @Test 36 public void testSaveUser() { 37 // 获取sqlSession,和spring整合后由spring管理 38 SqlSession sqlSession = this.sqlSessionFactory.openSession(); 39 // 从sqlSession中获取Mapper接口的代理对象 40 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 41 // 创建保存对象 42 User user = new User(); 43 user.setUsername("刘备"); 44 user.setBirthday(new Date()); 45 user.setSex('1'); 46 user.setAddress("蜀国"); 47 // 执行查询方法 48 userMapper.saveUser(user); 49 System.out.println(user); 50 // 和spring整合后由spring管理 51 sqlSession.commit(); 52 sqlSession.close(); 53 } 54 }
SqlMapConfig.xml配置文件
1.配置内容
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
2.properties(属性)
SqlMapConfig.xml可以引用Java属性文件中的配置信息如下:
在config下定义jdbc.properties文件,
内容:
1 jdbc.driver=com.mysql.jdbc.Driver 2 3 jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8 4 5 jdbc.username=root 6 7 jdbc.password=root
SqlMapConfig.xml引用如下:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 3 <!DOCTYPE configuration 4 5 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 6 7 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 8 9 <configuration> 10 11 12 13 <!-- 是用resource属性加载外部配置文件 --> 14 15 <properties resource="jdbc.properties"> 16 17 <!-- 在properties内部用property定义属性 --> 18 19 <!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 --> 20 21 <property name="jdbc.username" value="root123" /> 22 23 <property name="jdbc.password" value="root123" /> 24 25 </properties> 26 27 <!-- 和spring整合后 environments配置将废除 --> 28 29 <environments default="development"> 30 31 <environment id="development"> 32 33 <!-- 使用jdbc事务管理 --> 34 35 <transactionManager type="JDBC" /> 36 37 <!-- 数据库连接池 --> 38 39 <dataSource type="POOLED"> 40 41 <property name="driver" value="${jdbc.driver}" /> 42 43 <property name="url" value="${jdbc.url}" /> 44 45 <property name="username" value="${jdbc.username}" /> 46 47 <property name="password" value="${jdbc.password}" /> 48 49 </dataSource> 50 51 </environment> 52 53 </environments> 54 55 <mappers> 56 57 <mapper resource="sqlmap/user.xml"/> 58 59 <mapper resource="mapper/userMapper.xml"/> 60 61 </mappers> 62 63 </configuration>
注意:MyBatis将按照下面的顺序来加载属性:
1.在properties元素体内定义的属性首先被读取
2.然后会读取properties元素中resource或url加载的属性,他会覆盖已读取的同名属性。
mappers(映射器)
Mapper配置的几种方法
1. <mapper resource=" " />
使用相对于类路径的资源。如:<mapper resource="sqlmap/User.xml" />
2. <mapper class=" " />
使用mapper接口类路径。如:<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
3.<package name=""/>
注册指定包下的所有mapper接口。如:<package name="cn.itcast.mybatis.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

浙公网安备 33010602011771号