MyBatis的基本使用
1、MyBatis的基本介绍
1.1、MVC三层架构
MVC三层架构:M 数据访问层、V 界面层、C 业务逻辑层。
三层的职责:
- V 界面层:View 对数据的展示代码,比如JSP、html页面,就是专门用来展示数据,美化页面的。
- C 业务逻辑层:Controller 控制,接收界面层传递的数据,计算逻辑,调用数据访问层来获取数据并且交付给界面层展示。比如:Servlet、service
- M 数据访问层:Model 模型,代表着业务逻辑代码与数据库代码,就是访问数据,对数据库进行增删改查等等。
三层的处理请求的交互:
用户 ---> 界面层 ---> 业务逻辑层 ---> 数据访问层 ---> DB数据库
1.2、mybatis的基本介绍
为什么使用 mybatis ?在传统的 JDBC 中,我们除了需要自己提供 SQL 外,还必须操作 Connection、Statment、ResultSet,不仅如此,为了访问不同的表,不同字段的数据,我们需要些很多雷同模板化的代码,显得繁琐又枯燥。
而我们在使用了 MyBatis 之后,只需要提供 SQL 语句就好了,其余的诸如:建立连接、操作 Statment、ResultSet、释放资源、处理 JDBC 相关异常等等都可以交给 MyBatis 去处理,我们的关注点于是可以就此集中在 SQL 语句上,关注在增删改查这些操作层面上。mybatis 提供了循环 SQL,可以将查询的结果集封装为 java 对象、list 集合。并且 MyBatis 支持使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
2、mybatis 的基本使用
新建一个 maven JavaSE 项目。先需要添加依赖,除了 mybatis 依赖外还需要添加 mysql 的驱动依赖:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.12</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency>
新建一个 resources 目录,在该目录下添加 mybatis 的配置文件 mybatis-config.xml。
项目的最终目录结构如下:
mybatis-config.xml 配置文件文件的内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="sqlmap/user.xml"/> </mappers> </configuration>
上面的配置文件中,我们指定了一个 sql 映射文件 sqlmap/user.xml 文件。我们在 resources 目录下新建一个 sqlmap 目录,在该文件夹下建立 sql 的映射文件。
在 sqlmap 文件夹下建立 user.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"> <mapper namespace="user"> <select id="findUserById" resultType="entity.User"> select * from user where id = #{id} </select> <select id="findUserInfo" resultType="entity.User"> select id,name,password from user where id = #{id} </select> </mapper>
sql 映射文件中在 mapper 标签下写 sql 语句,mapper 标签的 namespace 指定命名空间,命名空间应该唯一,名称可以自定义。sql 语句中通过 id 唯一标识该语句,在使用 sql 时通过 “命名空间.id” 形式来使用。resultType 指定的是 select 语句的查询结果类型。
然后建一个实体类。我们要查询的是 user 表信息,该表结构如下:
所以我们建一个 User 实体类,该实体类必须有无参构造函数,否则可能会有问题。
package entity; public class User { private Integer id; private String name; private String password; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + '}'; } }
然后是 UserDao 接口类:
package dao; import entity.User; import java.io.IOException; public interface UserDao { User finUserById(Integer userId) throws IOException; }
UserDaoImpl 实现类:
package dao.impl; import dao.UserDao; import entity.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; public class UserDaoImpl implements UserDao { @Override public User finUserById(Integer userId) throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //获取sqlsession对象 SqlSession session = factory.openSession(); //执行sql语句。通过sql映射文件中,sql语句的标识来指定需要执行的sql语句 User resultUser = session.selectOne("user.findUserById", userId); //参数一:namespace.id //关闭sqlsession对象 session.close(); return resultUser; } }
最后通过一个单元测试类来测试:
package test; import dao.UserDao; import dao.impl.UserDaoImpl; import entity.User; import org.junit.Test; import java.io.IOException; public class Test01 { @Test public void test01() throws IOException { UserDao userDao = new UserDaoImpl(); User user = userDao.finUserById(1); System.out.println(user); } }
2.1、mybatis 查询
大致流程跟上面一样,只需修改 sql 映射文件如下:
<?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"> <mapper namespace="user"> <select id="findUserById" parameterType="int" resultType="entity.User"> select * from user where id = #{id} </select> <select id="listUser" resultType="entity.User"> select * from user </select> </mapper>
使用单元测试类来查询,查询语句如下:
public class Test01 { @Test public void test02() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //获取sqlsession对象 SqlSession session = factory.openSession(); //查询对象 User resultUser = session.selectOne("user.findUserById", 1); //参数一:namespace.id System.out.println("查询对象的结果:" + resultUser); //查询list集合 List list = session.selectList("user.listUser"); System.out.println("查询集合的结果:" + list); //关闭sqlsession对象 session.close(); } }
查询结果:
2.2、mybatis 增删改
增删改操作跟查询操作差不多,但是 mybatis 中默认是不会自动提交事务的,所以在进行增删改操作时一定要手动去提交事务,否则不会生效。
sql 映射文件如下:
<?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"> <mapper namespace="user"> <insert id="adduser" parameterType="entity.User"> insert into user (id, name, password) values (#{id},#{name},#{password}) </insert> <delete id="deleteuser" parameterType="entity.User"> delete from user where id = #{id} </delete> <update id="updateuser" parameterType="entity.User"> update user set name=#{name} where id=#{id} </update> </mapper>
在 sqlmapper 映射文件中,parameterType 指定的是要求输入参数的类型,resultType 指定的是输出的结果类型。
使用单元测试类来进行增删改,语句如下:
public class Test01 { @Test public void test03() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //获取sqlsession对象。 SqlSession session = factory.openSession(); //通过openSession()获取的是非自动提交的对象,可以通过openSession(true)来获取自动提交的sqlsession对象,这样就不用再手动commit了。 //增加操作 User user1 = new User(); user1.setId(6); user1.setName("newUser"); user1.setPassword("123"); int addResult = session.insert("user.adduser", user1); //一定要手动提交事务。或者最后再一起提交也行 session.commit(); System.out.println("增加操作的结果:" + addResult); //删除操作 User user2 = new User(); user2.setId(2); int delResult = session.delete("user.deleteuser", user2); //手动提交事务 session.commit(); System.out.println("删除操作的结果:" + delResult); //修改操作 User user3 = new User(); user3.setId(3); user3.setName("newName"); int updateResult = session.update("user.updateuser", user3); //手动提交事务 session.commit(); System.out.println("删除操作的结果:" + updateResult); //关闭sqlsession对象 session.close(); } }
mybatis 中通过 openSession() 默认获取的是非自动提交的对象,可以通过 openSession(true) 来获取自动提交的 sqlsession 对象,这样就不用再手动 commit 了。
操作结果:
3、mybaits 的配置文件
3.1、mybatis 配置文件
MyBatis 的配置文件 mybatis-config.xml 包含了数据库连接信息,同时还包含了 Mapper 映射文件的加载路径、全局参数以及类别别名等一系列MyBatis的核心配置信息。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--环境配置,即数据库的连接信息,可以配置多个。 default指定默认使用哪个数据库配置信息 --> <environments default="development"> <!--environment:一个数据库的配置信息。id指定该配置的名称,名称可自定义--> <environment id="development"> <!--transactionManager指定mybatis的事务管理器。type:jdbc 表示使用jdbc中的connection对象的commit、rollback做事务管理--> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <!--每个mapper标签指定一个sql映射文件的位置--> <mapper resource="sqlmap/user.xml"/> </mappers> </configuration>
MyBatis 使用场景: 在进行 MyBatis 开发时,我们的大部分精力都放在了 SQL 映射文件上。 MyBatis 的特点就是以 SQL 语句为核心的不完全的 ORM(关系型映射)框架。与 Hibernate 相比,Hibernate 的学习成本比较高,而 SQL 语句并不需要开发人员完成,只需要调用相关 API 即可。这对于开发效率是一个优势,但是缺点是没办法对 SQL 语句进行优化和修改。而 MyBatis 虽然需要开发人员自己配置 SQL 语句,MyBatis 来实现映射关系,但是这样的项目可以适应经常变化的项目需求。所以使用 MyBatis 的场景是:对 SQL 优化要求比较高,或是项目需求或业务经常变动。
3.1.1、使用独立的JDBC配置文件
我们可以把 jdbc 的配置单独作为一个配置文件,然后再在 mybatis 的配置文件中引入 jdbc 的配置文件作为 jdbc 的配置。
在 resource 目录下新建一个 jdbc.properties 配置文件:
该文件内容如下:
prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/test prop.username=root prop.password=123456s
在 mybatis 中引入该配置文件中的配置:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--引入jdbc配置文件。文件路径是相对于类根路径--> <properties resource="jdbc.properties"></properties> <!--环境配置,即数据库的连接信息,可以配置多个。 default指定默认使用哪个数据库配置信息 --> <environments default="development"> <!--environment:一个数据库的配置信息。id指定该配置的名称,名称可自定义--> <environment id="development"> <!--transactionManager指定mybatis的事务管理器。type:jdbc 表示使用jdbc中的connection对象的commit、rollback做事务管理--> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${prop.driverClass}"/> <property name="url" value="${prop.url}"/> <property name="username" value="${prop.username}"/> <property name="password" value="${prop.password}"/> </dataSource> </environment> </environments> <mappers> <!--每个mapper标签指定一个sql映射文件的位置--> <mapper resource="sqlmap/user.xml"/> <mapper resource="sqlmap/student.xml"/> </mappers> </configuration>
3.2、配置日志
在使用 mybatis 进行开发的时候,如果我们要想从 sql 的映射文件中找出最终执行的完整的 sql 会非常的难,这个时候我们可以通过配置日志来将最终执行的完整的 sql 打印出来。
配置日志只需在 mybatis 的配置文件中添加以下配置:
<!--配置日志--> <settings> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings>
配置文件示例:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--配置日志--> <settings> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="sqlmap/user.xml"/> </mappers> </configuration>
属性名:logImpl
描述:指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
有效值:SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
配置日志之后,我们通过 mybatis 执行 sql,可以在控制台看到日志输出信息,类似如下:
4、mapper代理开发模式
通过使用 Mapper 代理的开发方式,程序员只需要编写 mapper 的接口类(相当于dao接口)即可,而不用再写 dao 的实现类,这样能让代码更加方便简洁。Mybatis 会自动地为接口类生成动态代理实现类
不过要实现 mapper 代理的开发方式,需要遵循一些开发规范:
- sql mapper 映射文件的 namespace 写成接口类的完整类名。即 接口类的完整类名 == 映射文件的 namespace
- sql mapper 映射文件中的 sql 语句的 id 和接口类的方法名称相同。即 接口类的方法名 == 映射文件的 sql 的id
- 接口类的方法参数只能有一个,且类型要和 sql mapper 映射文件中 sql 语句的 parameterType 的值保持一致。即 接口类的方法的参数 == 映射文件的 sql 的 parameterType
- 接口类方法的返回值类型要和 sql mapper 映射文件中 sql 语句的 resultType 值或 resultMap 中的 type 值保持一致。即 接口类的返回值 == 映射文件的 sql 的 resultType
Mybatis 会自动地为接口类生成动态代理实现类,并创建该类的对象。
在调用方法时,mybatis 会根据接口类的方法名来找到 sql 映射文件中对应的 sql 语句。并且 mybatis 通过接口类中方法的返回值可以确定应该调用 sqlsession 中的那个方法来进行 sql 操作,比如如果返回值是 list,则调用 selectList() 方法
4.1、mapper 代理开发模式的使用
mapper 代理开发模式跟正常使用 mybatis 差不多,只不过 sql mapper 映射文件和接口类需要符合一定的规范。
实现示例:
下面操作的是 student 表,表结构如下:
首先建立 sql 映射文件,映射文件 namespace 应该是接口类的完整类名。映射文件 student.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"> <mapper namespace="dao.StudentDao"> <select id="findStudentById" parameterType="int" resultType="entity.Student"> select * from student where id = #{id} </select> <select id="findStudentAll" resultType="entity.Student"> select * from Student </select> <insert id="insertStudent" parameterType="entity.Student"> insert into Student(id,name,age) values(#{id},#{name},#{age}) </insert> <delete id="deleteStudentById" parameterType="int"> delete from Student where id=#{id} </delete> <update id="updateStudentName" parameterType="entity.Student"> update Student set name=#{name} where id=#{id} </update> </mapper>
下面建立 StudentDao 接口类,只需要接口类接口,无需书写实现类,Mybatis 会自动地为接口类生成动态代理实现类。
接口类的方法名、参数和返回值要和 sql 映射文件中定义的对应,StudentDao 接口类代码:
package dao; import entity.Student; import java.util.List; public interface StudentDao { public Student findStudentById(int id); public List<Student> findStudentAll(); public void insertStudent(Student Student); public void deleteStudentById(int id); public void updateStudentName(Student Student); }
然后就可以使用 mybatis 进行操作 sql 了。下面使用单元测试类进行测试:
public class Test02 { @Test public void test01() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = factory.openSession(); StudentDao studentDao = session.getMapper(StudentDao.class); //查询对象 Student student = studentDao.findStudentById(2); System.out.println(student); //查询集合 List list = studentDao.findStudentAll(); System.out.println(list); //增加 Student student1 = new Student(); student1.setName("aa"); student1.setAge(33); studentDao.insertStudent(student1); //删除 studentDao.deleteStudentById(2); //修改 Student student2 = new Student(); student2.setId(1); student2.setName("newName"); studentDao.updateStudentName(student2); //需要手动提交事务 session.commit(); session.close(); } }