MyBatis入门
文章目录
mybatis通过xml或注解的方式将各种statement配置起来,并通过java对象和statement中sql的动态参数映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象或者是集合(使用了ORM思想对结果集进行封装)并返回。
MyBatis的环境搭建
1.准备数据库以及创建Maven工程
IDEA新建项目,选择maven项目,不需要勾选任何东西 ,直接进行创建。
用sql文件创建数据库以及下面的表。Mybatisdb.sql
CREATE DATABASE MyBatisdb;
USE MyBatisdb;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'张三','2018-02-27 17:47:08','男','北京'),(42,'李四','2018-03-02 15:09:37','女','北京'),(43,'王五','2018-03-04 11:34:34','女','北京'),(45,'赵六','2018-03-04 12:04:06','男','陕西'),(46,'安','2018-03-07 17:37:26','男','北京'),(48,'权','2018-03-08 11:44:00','女','陕西');
在pom.xml下
- 添加加一个打包方式
<packaging>jar</packaging>
- 引入最新的mybatis依赖
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
- 还需要数据库操作的mysql依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
- 如果需要日志的话要导入log4j
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
- 如果需要单元测试需要导入junit
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
2.创建实体类和dao的接口
-
创建实体类
下面是在java下的com.annan.domain中 User.java 对应接口是com.annan.dao下的UserDao
package com.annan.domain; import java.io.Serializable; import java.util.Date; public class User implements Serializable { private Integer id; private String username; private Date birthday; private String sex; private String address; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}'; } }
-
在com.annan.dao下创建接口UserDao.java
package com.annan.dao; import com.annan.domain.User; import java.util.List; public interface UserDao { /** * 查询所有操作 * @return */ List<User> findAll(); }
实体类是什么?
首先,直观的看:
实体类就是一个拥有Set和Get方法的类。实体类通常总是和数据库之类的(所谓持久层数据)联系在一起。这种联系是借由框架(如Hibernate)来建立的。
其次说定义(比较生涩难懂):
实体类主要是作为数据管理和业务逻辑处理层面上存在的类别; 它们主要在分析阶段区分 实体类的主要职责是存储和管理系统内部的信息,它也可以有行为,甚至很复杂的行为,但这些行为必须与它所代表的实体对象密切相关。
这段话看起来不太好懂,应该结合实体类的作用来看:
实体类的作用(需要面向对象的一点很基本的知识):
实体类就是一个载体。
现在的设计差不多都是一张表就等于业务里面的一个类。一条记录(一般一行数据)是一个对象,一行中的一列就是这个对象的一个属性。
所以我们在操作某个表时(比如更改这个表的信息),我们就可以在前台定义一个这样的对象,然后将其对应的属性赋值,然后传到后台。
这样后台就可以拿到这个对象的所有值了——不用一个一个属性当参数传过来,只要传一个这个类的对象就好了,也就是说只要一个参数就好了。好处不言而喻。
而这种前台对象到后台数据库的联系,我们是借由框架、配置文件来配置实现的,很方便快捷。并不需要自己手动编程实现。
简而言之,(大多数情况下)实体类就是数据库在Java代码中对应的东东。
最后,摘抄一点JavaPeak大大使用实体类的经验:
一、实体类的名字尽量和数据库的表的名字对应相同。
二、实体类应该实现java.io.Serializable接口。
三、实体类应该有个无参的构造方法。
四、实体类应该有个有参(所有的参数)的构造方法。
五、实体类有属性和方法,属性对应数据库中表的字段,方法主要有getter和setter方法。
六、实体类还应该有个属性serialVersionUID。
例如:private static final long serialVersionUID = -6125297654796395674L;
七、属性一般是private类型,方法为public类型,对于数据库自动生成的ID字段对应的
属性的set方法为private。
实体类的变量对应表中的字段。实体类需要继承implements Serializable 为了序列化(https://blog.csdn.net/tree_ifconfig/article/details/82766587)。写出所有变量的getter和setter,然后tostring。
接口UserDao,这个是在dao包里面的
写以下是为了查询所有
List<User> findAll();
idea 快捷键为:Alt+Insert 快速写出getter和setter方法
3.创建MyBatis的主配置文件 SqlMapConfig.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">
-
在约束头下面配置(如果没出代码块提示看一下maven导包有没有问题)
<!--主配置文件--> <configuration> <!-- 配置环境 这里default任意填--> <environments default="mysql"> <!-- 配置mysql的环境 id要与default一致--> <environment id="mysql"> <!-- 配置事务类型 这里事务类型选择JDBC--> <transactionManager type="JDBC"></transactionManager> <!-- 配置数据源(连接池)类型是POOLED 池类型--> <dataSource type="POOLED"> <!-- 配置数据库的四个基本信息--> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!-- 还需要指定映射配置文件的位置,映射配置文件是说每个dao独立的配置文件--> <mappers> <mapper resource="com/annan/dao/UserDao.xml"></mapper> </mappers> </configuration>
4.创建映射配置文件(Mapper) UserDao.xml,是在resource下建的
路径就是主配置文件中声明的位置。
-
首先导入mapper的头部约束
<?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
<mapper namespace="com.annan.dao.UserDao"> <select id="findAll" > select * from user </select> </mapper>
注释:
mapper中的namespace:名称空间,此处要写的是接口的全限定类名(类名全称,包用 . 隔开),相当于是告诉MyBatis这个配置文件是为了实现哪个接口的。
select中的id:是接口UserDao中
List<User> findAll();
中的findAll方法名。必须一一对应。mapper的namespace:用来绑定对应接口,mybatis会通过该绑定自动帮你找到对应要执行的SQL语句。
namespace和id的关系:光靠id (findAll)是无法定位到UserDao中声明的findAll的,原因是因为有很多类都会声明findAll这种方法,所以需要带上namespace,这样可以唯一确定的实现对应的findAll方法。
在select语句块中要写的是sql语句,这里sql语句结尾有无分号都可以。
文件目录展示
注意
创建UserDao.xml和UserDao.java命名相同是因为保持一致,在MyBatis中把持久层的操作接口名称和映射文件也叫做Mapper,也就是说映射文件或接口叫UserDao和UserMapper是一样的。
-
在idea中创建文件夹(Directory)和包(Package)是不一样的。
包在创建的时候:com.annan.dao是三级目录,但是目录如果直接用com.annan.dao就只有一级目录。 -
当遵循以下三点(约定)后,在开发中就不需要写dao的实现类。
-
MyBatis的映射配置文件位置必须和dao接口包的结构相同,UserDao.java(接口)在src->main->com.annan.dao下,UserDao.xml(mapper映射)也要在resources->com.annan.dao下
-
映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名。全限定类名:就是用.隔开的类名,比如:
com.annan.dao
-
映射配置文件的操作配置,id的取值必须是对应dao接口的方法名。
-
MyBatis的入门案例
目的:测试是否拿到了语句执行后的结果集。
-
在resources的根目录下创建log4j.properties(约定如此,注意检查是否引入了log4j日志的依赖)
# Set root category priority to INFO and its only appender to CONSOLE. #log4j.rootCategory=INFO, CONSOLE debug info warn error fatal log4j.rootCategory=debug, CONSOLE, LOGFILE # Set the enterprise logger category to FATAL and its only appender to CONSOLE. log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n # LOGFILE is set to be a File appender using a PatternLayout. log4j.appender.LOGFILE=org.apache.log4j.FileAppender log4j.appender.LOGFILE.File=d:\axis.log log4j.appender.LOGFILE.Append=true log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
-
在test的java下创建包com.annan.test,再创建文件,MyBatisTest.java
public class MyBatisTest { //入门案例 public static void main(String[] args) throws Exception { // 1.读取配置文件 加载主配置文件信息 此处会有异常 throws掉 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); // 2.创建SqlSessionFactory工厂 设计模式 SqlSessionFactory是一个接口不能new SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); // 3.创建工厂生产SqlSession对象 这个对象是为了提供dao的实现 SqlSession session = factory.openSession(); // 4.使用SqlSession创建Dao接口 动态代理 引入import com.annan.dao.UserDao; 传入dao UserDao userDao = session.getMapper(UserDao.class); // 5.使用代理对象执行方法 增删改查方法 这里需要在对应的xml中设置返回类型为User类(不然mybatis不知道你往哪封装) 此处users是sql语句执行后返回的结果集 List<User> users = userDao.findAll(); for (User user:users){//遍历 System.out.println(user); } // 6.释放资源 session.close(); in.close(); } }
对应代码注释 5 。需要设置xml的resultType 配置过程中需要说将结果集封装到哪里; 注意,如果返回的是集合,那应该设置为集合包含的类型(User),而不是集合本身的类型(List)。 同时,resultType 和 resultMap 之间只能同时使用一个。
<?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的约束--> <mapper namespace="com.annan.dao.UserDao"> <!-- 返回类型指定为User类型 将结果集封装到user对象中,将这个对象添加到list当中--> <select id="findAll" resultType="com.annan.domain.User"> select * from user </select> </mapper>
-
结果
测试过程总结
-
读取配置文件
-
创建SqlSessionFactory工厂
-
创建SqlSession
-
创建Dao接口的代理对象
-
执行dao中方法
-
释放资源
注意:要在映射配置文件中告诉mybatis要封装到哪个实体类中(resultType),要用全限定类名.
使用注解方式mybatis入门案例
当说到用注解的时候,也就是说xml没有用了。主配置文件是不能动的
-
删掉UserDao.xml,在接口类UserDao中添加注解
@Select("select * from user")
package com.annan.dao; import com.annan.domain.User; import org.apache.ibatis.annotations.Select; import java.util.List; public interface UserDao { @Select("select * from user") List<User> findAll(); }
-
修改SqlMapConfig.xml中的映射配置文件,resource改为class
原本 resource是对应配置文件(这时候配置文件已经删了。)
<mappers> <mapper resource="com/annan/dao/UserDao.xml"></mapper> </mappers>
改为 class对应接口(因为此时使用的是注解了)
<mappers> <mapper class="com.annan.dao.UserDao"></mapper> </mappers>
-
运行程序
-
总结
不需要用xml配置那么多东西,比如select的id还有封装的结果集类型,添加注解后,要在主配置文件中修改mapper的映射。
实际开发中越简单越好,所以不采用写dao实现类的方式,但是mybatis支持dao实现类
入门案例设计模式分析
public class MyBatisTest {
//入门案例
public static void main(String[] args) throws Exception {
// 1.读取配置文件 加载主配置文件信息 此处会有异常 throws掉
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.创建SqlSessionFactory工厂 设计模式 SqlSessionFactory是一个接口不能new
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
// 3.创建工厂生产SqlSession对象 这个对象是为了提供dao的实现
SqlSession session = factory.openSession();
// 4.使用SqlSession创建Dao接口 动态代理 引入import com.annan.dao.UserDao; 传入dao
UserDao userDao = session.getMapper(UserDao.class);
// 5.使用代理对象执行方法 增删改查方法 这里需要在对应的xml中设置返回类型为User类(不然mybatis不知道你往哪封装)
List<User> users = userDao.findAll();
for (User user:users){//遍历
System.out.println(user);
}
// 6.释放资源
session.close();
in.close();
}
}
-
读取主配置文件。这里用的不是绝对路径和相对路径
绝对路径:换一个电脑就可能出问题
相对路径: web工程一部署src就没了,也用不了
读配置文件只有两个方法:
- 使用类加载器,只能读取类路径的配置文件。代码中用的是类加载器
- 使用ServletContext对象的getRealPath()当前应用部署的绝对路径,项目在哪路径就在哪。
-
创建工厂 mybatis 使用了构建者模式 隐藏创建的过程,让使用者直接调用方法就可以拿到对象
建工厂,把厂子包给包工队builder:SqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
负责给钱 in
SqlSessionFactory factory = builder.build(in);
此处builder就是构建者生产SqlSession 使用了工厂模式不用new来生产,用工厂模式生产,解决类之间的依赖关系,解耦。
-
使用了代理模式
UserDao userDao = session.getMapper(UserDao.class);
创建Dao接口实现类使用了代理模式。优势:在不修改源码的基础上对已有方法增强。 -
为什么不封装这些模式,是为了提高代码的灵活性,有很多重载方法。