Mybatis(一)实现单表的增删改查
1.1 什么是Mybatis
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。
MyBatis参考资料官网:https://mybatis.github.io/mybatis-3/zh/index.html。
官网对Mybatis的介绍更加具有权威性:
- MyBatis 是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。
- MyBatis 避免了几乎所有的 JDBC 代码和手工设置参数以及抽取结果集。
- MyBatis 使用简单的 XML 或注解来配置和映射基本体,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
MyBatis优点:
1、简单易学
mybatis本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
2、灵活
mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
3、解除sql与程序代码的耦合
通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。对开发人员而言,核心sql还是需要自己优化:sql和java编码分开,功能边界清晰,一个专注业务、 一个专注数据。
4、提供映射标签,支持对象与数据库的orm字段关系映射。
5、提供对象关系映射标签,支持对象关系组建维护。
6、提供xml标签,支持编写动态sql。
MyBatis缺点:
1、编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。
2、SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
3、框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
MyBatis与JDBC比较:
SQL夹在Java代码块里,耦合度高导致硬编码内伤,维护不易且实际开发需求中sql是有变化,频繁修改的情况多见。
MyBatis与Hibernate和JPA比较:
长难复杂SQL,对于Hibernate而言处理也不容易,内部自动生产的SQL,不容易做特殊优化。基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。 导致数据库性能下降。
MyBatis与iBatis比较:
MyBatis是iBatis的升级版,用法有很多的相似之处,但是MyBatis进行了重要的改进。
1、Mybatis实现了接口绑定,使用更加方便。
在ibatis2.x中我们需要在DAO的实现类中指定具体对应哪个xml映射文件, 而Mybatis实现了DAO接口与xml映射文件的绑定,自动为我们生成接口的具体实现,使用起来变得更加省事和方便。
2、对象关系映射的改进,效率更高。
3、MyBatis采用功能强大的基于OGNL的表达式来消除其他元素。
1.2 开发第一个Mybatis查询
- 新建一个java工程
- 添加jar包,如下图:
- 新建包,管理代码
- 建库,建表
1 DROP TABLE IF EXISTS `t_user`; 2 CREATE TABLE `t_user` ( 3 `t_id` int(11) NOT NULL AUTO_INCREMENT, 4 `t_username` varchar(20) NOT NULL, 5 `t_password` varchar(8) NOT NULL, 6 PRIMARY KEY (`t_id`) 7 ) 8 9 -- ---------------------------- 10 -- Records of t_user 11 -- ---------------------------- 12 INSERT INTO `t_user` (t_username,t_password) VALUES ( 'lisi', '123456'); 13 INSERT INTO `t_user` (t_username,t_password) VALUES ( 'wanger', '654321'); 14 INSERT INTO `t_user` (t_username,t_password) VALUES ( '李四', '123123'); 15 INSERT INTO `t_user` (t_username,t_password) VALUES ( '王二', '321321');
5.在src目录下添加全局配置文件config.xml和log4j.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 <!-- 7 default="development" 开发环境 8 default="work" 发布环境 9 --> 10 11 <environments default="development"> 12 13 <environment id="development"> 14 15 <!-- 配置事物 --> 16 <transactionManager type="JDBC"></transactionManager> 17 18 <!-- 配置数据源 --> 19 <dataSource type="POOLED"> 20 <property name="driver" value="com.mysql.jdbc.Driver"/> 21 <property name="url" value="jdbc:mysql://192.168.61.22:3306/test" /> 22 <property name="username" value="root"/> 23 <property name="password" value="123456"/> 24 25 </dataSource> 26 27 </environment> 28 29 </environments> 30 31 32 </configuration>
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 3 4 <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 5 6 <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"> 7 <param name="Encoding" value="UTF-8" /> 8 <layout class="org.apache.log4j.PatternLayout"> 9 <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" /> 10 </layout> 11 </appender> 12 <logger name="java.sql"> 13 <level value="debug" /> 14 </logger> 15 <logger name="org.apache.ibatis"> 16 <level value="info" /> 17 </logger> 18 <root> 19 <level value="debug" /> 20 <appender-ref ref="STDOUT" /> 21 </root> 22 </log4j:configuration>
6.编写java实体类,生成set,get方法
1 public class User { 2 3 private Integer id; 4 private String username; 5 private String password; 6 7 } 8
7.编写sql映射文件—————mapper文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > 3 4 <!-- 配置SQL语句,与实体类操作的对应关系。 --> 5 <!-- 保证唯一性 --> 6 <mapper namespace="com.softjx.model.UserMapper"> 7 8 <!-- 9 将返回的数据 与对象对应。将返回的数据,按照配置组装成对应的对象。 10 --> 11 <select id="selectAll" resultType="com.softjx.model.User"> 12 select t_id as id,t_username as username,t_password password from t_user 13 </select> 14 15 <select id="selectById" resultType="com.softjx.model.User"> 16 select t_id as id,t_username as username,t_password password from t_user where t_id=#{id}; 17 </select> 18 19 </mapper>
8.在全局配置文件中添加mapper文件的位置
<!-- 导入映射文件 --> <mappers> <mapper resource="com/softjx/model/UserMapper.xml" /> </mappers>
9.编写测试代码:
1 public class TestMybatis { 2 private SqlSession session; 3 4 @Before 5 public void read() throws Exception { 6 // 构建mybatis的执行对象 7 FileInputStream fis = new FileInputStream("src/config.xml"); 8 SqlSession session = new SqlSessionFactoryBuilder().build(fis) 9 .openSession(); 10 11 // InputStream inputStream = 12 // Resources.getResourceAsStream("config.xml"); 13 // SqlSession session = new 14 // SqlSessionFactoryBuilder().build(inputStream).openSession(); 15 this.session = session; 16 } 17 18 @Test 19 public void TestSelectAll() { 20 System.out.println("查询所有用户"); 21 try { 22 List<User> users = session 23 .selectList("com.softjx.model.UserMapper.selectAll");// 根据字符找sql语句 24 25 for (User user : users) { 26 System.out.println(user.getId() + " " + user.getUsername() 27 + " " + user.getPassword()); 28 } 29 } finally { 30 session.close(); 31 } 32 33 } 34 35 @Test 36 public void TestSelectById() { 37 System.out.println("查询所有用户"); 38 try { 39 User user = session 40 .selectOne("com.softjx.model.UserMapper.selectById",2);// 根据字符找sql语句 41 42 System.out.println(user.getId() + " " + user.getUsername() + " " 43 + user.getPassword()); 44 45 } finally { 46 session.close(); 47 } 48 49 } 50 51 }
10.SqlSession
SqlSession 的实例不是线程安全的,因此是不能被共享的。
SqlSession每次使用完成后需要正确关闭,这个关闭操作是必须的。
1.3 第一个Mybatis程序出错地方
1.全局配置文件没有指定mapper文件。
2.数据库配置出错。
3.jdbc驱动没有加载。
4.select 查询语句没有转化javabean中属性。
5.全局配置文件路径不对。
6.log4j.xml文件没有。
7.id名称写错了。
1.4Mybatis添加,修改,删除
Mapper.xml文件的添加,修改,删除
1 <insert id="insertUser"> 2 insert into t_user (t_username,t_password) 3 values (#{username},#{password}) 4 </insert> 5 6 <update id="updateUser"> 7 update t_user set 8 t_username = #{username}, 9 t_password = #{password} 10 where t_id = #{id} 11 </update> 12 13 <delete id="deleteUser"> 14 delete from t_user where t_id = #{id} 15 </delete>
测试添加,修改,删除
1 @Test 2 public void TestInserUser() { 3 System.out.println("添加一个用户"); 4 try { 5 User user=new User(); 6 user.setUsername("pkd"); 7 user.setPassword("888888"); 8 int count=session.insert("com.softjx.model.UserMapper.insertUser",user);// 根据字符找sql语句 9 session.commit(); 10 System.out.println(count); 11 } finally { 12 session.close(); 13 } 14 15 } 16 17 18 19 @Test 20 public void TestUpdateUser() { 21 System.out.println("更新一个用户"); 22 try { 23 User user=new User(); 24 user.setId(1); 25 user.setUsername("pkd"); 26 user.setPassword("888888"); 27 int count=session.update("com.softjx.model.UserMapper.updateUser",user);// 根据字符找sql语句 28 session.commit(); 29 System.out.println(count); 30 } finally { 31 session.close(); 32 } 33 34 } 35 36 37 38 @Test 39 public void TestDeleteUser() { 40 System.out.println("更新一个用户"); 41 try { 42 int count=session.delete("com.softjx.model.UserMapper.deleteUser",1);// 根据字符找sql语句 43 session.commit(); 44 System.out.println(count); 45 } finally { 46 session.close(); 47 } 48 49 }
1.5 Mybatis接口式编程CRUD
- 编写接口文件,作为dao层,只有定义接口,没有实现,其实现交给mapper.xml文件。
- 编写mapper.xml,注意其命名空间要是接口的路径。
- mapper.xml文件中sql语句与以前一样。
- 测试代码中使用接口的代理类对象,调用接口中的方法,实现数据处理。使用SqlSession获取映射器进行操作
接口代码:
1 public interface UserMapper { 2 3 4 //查询所有用户 5 public List<User> selectAll(); 6 7 //查询所有用户 8 public List<User> selectAll1(); 9 10 //查询一个用户 11 public User selectById(Integer id); 12 13 //添加用户 14 public int insertUser(User user); 15 16 //修改用户 17 public int updateUser(User user); 18 19 //删除用户 20 public int deleteUser(Integer id); 21 22 23 }
Mapper.xml映射文件:
1 <!-- 使用接口方式 加载命名空间 使用代理模式 --> 2 <mapper namespace="com.softjx.dao.UserMapper"> 3 4 5 6 <!-- 查询数据表中的所有记录,并封装User对象集合 --> 7 <select id="selectAll" resultType="com.softjx.model.User"> 8 select t_id as id,t_username as username,t_password password from t_user 9 </select> 10 11 <select id="selectAll1" resultType="com.softjx.model.User"> 12 select * from t_user1 13 </select> 14 15 16 <!-- 根据id查询数据表中的一条记录,并封装User对象 --> 17 <select id="selectById" resultType="com.softjx.model.User"> 18 select t_id as id,t_username as username,t_password password from t_user where t_id=#{id}; 19 </select> 20 21 22 <!-- 添加用户 --> 23 <insert id="insertUser"> 24 insert into t_user (t_username,t_password) 25 values (#{username},#{password}) 26 </insert> 27 28 29 <!-- 更新用户 --> 30 <update id="updateUser"> 31 update t_user set t_username=#{username},t_password=#{password} 32 where t_id=#{id} 33 </update> 34 35 36 <!-- 删除用户 --> 37 <delete id="deleteUser"> 38 delete from t_user where t_id=#{id} 39 </delete>
测试代码:
//查询所有 @Test public void TestSelectAll1() { System.out.println("查询所有用户"); //获取接口的实现类对象 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法 try { UserMapper mapper=session.getMapper(UserMapper.class); System.out.println(mapper); List<User> users=mapper.selectAll(); System.out.println(users); for (User user : users) { System.out.println(user.getId() + " " + user.getUsername() + " " + user.getPassword()); } } finally { session.close(); } } //查询一个用户 @Test public void TestSelectById() { System.out.println("查询一个用户"); //获取接口的实现类对象 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法 try { UserMapper mapper=session.getMapper(UserMapper.class); User user=mapper.selectById(2); System.out.println(user); System.out.println(user.getId() + " " + user.getUsername() + " " + user.getPassword()); } finally { session.close(); } } //添加用户测试 @Test public void TestInserUser() { System.out.println("添加一个用户"); try { User user=new User(); user.setUsername("pppp"); user.setPassword("666666"); UserMapper mapper=session.getMapper(UserMapper.class); int count=mapper.insertUser(user); session.commit();//这里一定要提交,不然数据进不去数据库中 //session.rollback(); System.out.println(count); } finally { session.close(); } } //修改用户测试 @Test public void TestUpdateUser() { System.out.println("修改用户"); try { User user=new User(); user.setId(10); user.setUsername("yyy"); user.setPassword("11111"); UserMapper mapper=session.getMapper(UserMapper.class); int count=mapper.updateUser(user);// 根据字符找sql语句 session.commit(); //session.rollback(); System.out.println(count); } finally { session.close(); } } //删除用户测试 @Test public void TestDeleteUser() { System.out.println("删除用户"); try { UserMapper mapper=session.getMapper(UserMapper.class); int count=mapper.deleteUser(10);// 根据字符找sql语句 session.commit(); //session.rollback(); System.out.println(count); } finally { session.close(); } }
总结:
1.SqlSession 的实例不是线程安全的,因此是不能被共享的。
2.SqlSession每次使用完成后需要正确关闭,这个关闭操作是必须的。
3.SqlSession可以直接调用方法的id进行数据库操作,但是我们一般还是推荐使用SqlSession获取到Dao接口的代理类,执行代理对象的方法,可以更安全的进行类型检查操作。