1.简介
1.1 什么是Mybatis?
Mybatis是一款优秀的持久层框架 它支持定制化SQL、存储过程以及高级映射 Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集 Mybatis可以使用简单的XML或注解来配置和映射原生类型、接口和Java的pojo为数据库中的记录
1.2 如何获得Mybatis?
maven仓库
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
Github: https://github.com/mybatis/mybatis-3/releases MyBatis文档网址:https://mybatis.org/mybatis-3/zh/index.html
2. 创建第一个Mybatis程序
2.1 搭建环境
1.新建一个普通的maven项目 2.删除src目录 3.加入maven依赖
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2.2 创建一个模块
1.编写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>
<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/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/liu/dao/UserMapper.xml" />
</mappers>
</configuration>
2.编写mybatis工具类
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
2.3 编写代码
1.编写实体类(一个实体类对应一个表)
package com.liu.pojo;
public class User {
public int id;
public String name;
public String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getPwd() {
return pwd;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
2.编写Dao接口
public interface UserDao {
List<User> getUserList();
}
3.编写接口对应的Mapper.xml文件(以前是一个UserDaoImpl对应一个UserDao,现在是一个Mapper.xml文件对应一个UserDao)
<?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="com.liu.dao.UserDao">
<select id="getUserList" resultType="com.liu.pojo.User">
select * from mybatis.user
</select>
</mapper>
2.4 测试
构造尽量保持规范,在test下建立com.liu.dao,并编写测试类UserDaoTest
public class UserDaoTest {
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userlist = userDao.getUserList();
for (User user : userlist) {
System.out.println(user);
}
sqlSession.close();
}
}
2.5 注意点
1.每一个Mapper.xml都需要在Mybatis核心配置文件中注册!
<mappers>
<mapper resource="com/liu/dao/UserMapper.xml" />
</mappers>
2.maven由于他的约定大于配置,可能会遇到我们写的配置文件(.xml或者.properties)无法被导出或者生效的问题,解决方案为在pom文件中贴如下代码:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
3.空指针问题:可能是重复定义了某变量所致
3.CRUD
3.1 namespace
namepspace中的包名要和Dao/Mapper接口的包名一致!
3.2 select
选择,查询语句;
- id:就是对应的namespace中绑定的Mapper接口中的方法名
- resultType:sql语句执行后的返回值
- parameterType:参数类型
- 通过 #{} 来取传递的参数
编写接口
User getUserById(int id);
编写对应的mapper中的sql语句
<select id="getUserList" resultType="com.liu.pojo.User">
select * from mybatis.user
</select>
测试
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user=mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
3.3 insert
编写接口
int addUser(User user);
编写对应的mapper中的sql语句
<insert id="addUser" parameterType="com.liu.pojo.User">
insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd})
</insert>
测试
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.addUser(new User(4,"哈哈","123333"));
if(res>0)
System.out.println("插入成功!");
sqlSession.commit();
sqlSession.close();
}
3.4 update
编写接口
int updateUser(User user);
编写对应的mapper中的sql语句
<update id="updateUser" parameterType="com.liu.pojo.User">
update mybatis.user set name = #{name}, pwd = #{pwd} where id = #{id}
</update>
测试
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res=mapper.updateUser(new User(4,"呵呵","111111"));
if(res>0)
System.out.println("修改成功!");
sqlSession.commit();
sqlSession.close();
}
3.5 delete
编写接口
int deleteUser(int id);
编写对应的mapper中的sql语句
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id = #{id}
</delete>
测试
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res=mapper.deleteUser(4);
if(res>0)
System.out.println("删除成功");
sqlSession.commit();
sqlSession.close();
}
注意点:增删改需要提交事务!!
3.6 万能的Map
假设我们的实体类,或者数据库中的表,字段或者参数过多,则应当考虑使用map。与直接传递对象的区别就在于使用map不一定要获取到所有的属性,而当使用User时,必须将所有的属性包揽在内
1.接口中参数声明为Map形式
int updateUser2(Map<String,Object> map);
2.Mapper中:参数类型是小写的map, 里面的值是map的key
<update id="updateUser2" parameterType="map">
update mybatis.user set name= #{name} where id=#{id}
</update>
3.测试代码
@Test
public void updateUser2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map=new HashMap<String, Object>();
map.put("id",1);
map.put("name","刘梦豪");
mapper.updateUser2(map);
sqlSession.commit();
sqlSession.close();
}
总结
Map传递参数,直接在sql中取出key即可!【parameterType=“map”】 #{key} 即可取到 对象传递参数,直接在sql中取对象的属性即可!【parameterType=“Object”】 #{对象包含的属性名}即可取到
对于方法中只有一个基本类型参数的情况下,可以直接在sql中取到! #{参数名} 对于方法中多个参数:用Map,或者注解@Param("") 后续会讲到
3.7 模糊查询
1.编写接口
List<User> getUserLike(String value);
2.编写对应的mapper中的sql语句并测试 方式一:
<select id="getUserLike" resultType="com.liu.pojo.User">
select * from mybatis.user where name like #{value}
</select>
对应的测试代码为:
@Test
public void getUserLike(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserLike("%李%");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
方式二:
<select id="getUserLike" resultType="com.liu.pojo.User">
select * from mybatis.user where name like "%"#{value}"%"
</select>
对应的测试代码为:
@Test
public void getUserLike(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserLike("李");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
4. 配置分析
4.1 核心配置文件
一般命名为:mybatis-config.xml
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
4.2 环境配置(environments)
MyBatis 可配置成适应多种环境 但是尽管可以配置多种环境,但每个 SqlSessionFactory 实例只能选择一种环境!
4.3 属性(properties)
我们可以通过properties来实现引用配置文件,这些属性都是可以外部配置且可动态替换的。既可以在典型的Java属性文件中配置,也可以通过properties元素的子元素来传递(db.properties)
编写一个配置文件 在核心配置文件中可引入外部配置文件 如果里面和外面的配置冲突了,优先使用外面的配置
4.4 类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。 第一种写法:
<typeAliases>
<typeAlias type="com.liu.pojo.User" alias="User"/>
...
</typeAliases>
第二种写法:扫描一个包,每个实体类的默认别名就为这个类的类名,首字母一般小写!(大写也行)
<typeAliases>
<package name="com.liu.pojo"/>
</typeAliases>
第三种写法:注解方式(在第二种写法的基础上,如果要修改名时则使用,如果一三写法同时使用,第一种生效) 直接在类的上面使用注解@Alias(“自定义名称”)
@Alias("hello")
public class User {
...
}
4.5 映射器(mappers)
每一个mapper都需要注册,注册mapper有三种方式 方式一:使用相对于类路径的资源引用
<configuration>
<mappers>
<mapper resource="com/liu/dao/UserMapper.xml"/>
...
</mappers>
</configuration>
方式二:使用映射器接口实现类的完全限定类名
<mappers>
<mapper class="com.liu.dao.UserMapper"/>
...
</mappers>
方式三:使用扫描包进行注入
<mappers>
<package name="com.liu.dao"/>
...
</mappers>
后两种方式的注意点:
- 接口和他的Mapper配置文件必须同名!
- 接口和他的Mapper配置文件必须在同一个包下!
5. 生命周期
SqlSessionFactoryBuilder:
- 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory:
- 说白了就是可以想象为:数据库连接池
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次创建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。
- 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession:
- 是连接到连接池的一个请求
- 每个线程都应该有它自己的 SqlSession 实例。
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 用完之后需要赶紧关闭,否则资源被占用!
这里面的每一个Mapper,就代表一个具体的业务!
6. 结果集映射(resultMap)
当表的字段名与实体类字段名不对应的时候,要进行映射。(在mapper.xml文件中) 实体类对应属性名property,数据库字段名column
<resultMap id="UserMap" type="user">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password" />
</resultMap>
sql语句中的resultType改为resultMap
<select id="getUserById" resultMap="UserMap">
select * from mybatis.user where id=#{id}
</select>
7.日志
如果一个数据库操作出现了异常,我们需要排错。日志就是最好的助手。 一般采用日志工厂来解决。掌握(STDOUT_LOGGING和LOG4J) 在Mybatis中具体使用哪一日志,需要在设置中设定!
7.1 标准的日志工厂实现(STDOUT_LOGGING)
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
7.2 Log4j
什么是Log4j?
- Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
- 我们可以控制每一条日志的输出格式
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
1.先导入log4j依赖
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
2.在resources下增加文件log4j.properties(可以写成其他的)
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置;第二行表示日志会被保存在的位置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/liu.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3.在mybatis核心配置文件中配置log4j为日志实现
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
4.简单使用
-
在需要使用log4j的类中,导入包 import org.apache.log4j.Logger; -
获取日志对象,参数为当前类的class static Logger logger = Logger.getLogger(UserMapperTest.class);
-
举例 public class UserMapperTest {
static Logger logger = Logger.getLogger(UserMapperTest.class);
@Test
public void log4jTest(){
logger.info("info:进入了testLog4j");
logger.debug("debug:进入了testLog4j");
logger.error("error:进入了testLog4j");
}
}
8. 分页
为什么要分页?
limit语法: 对于一个参数的情况就是显示出前n行数据
select * from product limit n;
limit有两个参数,第一个参数表示从第几行数据开始查(startIndex),第二个参数表示每页的大小(pageSize)
select * from product limit 3,2;
1.定义接口
List<User> getUserByLimit(Map<String,Integer> map);
2.在mapper.xml文件实现
<resultMap id="UserMap" type="user">
<result column="pwd" property="password" />
</resultMap>
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user limit #{startIndex},#{pageSize};
</select>
3.测试
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex",1);
map.put("pageSize",2);
List<User> userlist = mapper.getUserByLimit(map);
for (User user : userlist) {
System.out.println(user);
}
sqlSession.close();
}
还有一种分页方式不需要写sql代码,通过RowBounds实现
9. 注解
9.1 注解开发
1.注解形式:(在接口文件里面方法上直接添加注解)
public interface UserMapper {
@Select("select * from user")
List<User> getUsers();
}
2.在mybatis-config.xml文件中添加类路径映射,绑定接口
<mappers>
<mapper class="com.liu.dao.UserMapper"/>
</mappers>
本质:利用Java反射 底层:代理 注意: 使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
|