官方中文手册:https://mybatis.org/mybatis-3/zh/getting-started.html
创建Maven工程
导入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.bnzrgroupId>
<artifactId>Myabtis-StudyartifactId>
<packaging>pompackaging>
<version>1.0-SNAPSHOTversion>
<modules>
<module>mybatis-01module>
modules>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.27version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.9version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
dependency>
dependencies>
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
project>
在resource文件夹内创建mybatis核心配置文件mybatis-config.xml(名字可以改)
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/bnzr/dao/UserMapper.xml"/>
mappers>
configuration>
package com.bnzr.utils;
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;
//SqlSessionFactory --> SqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
/**
* 使用Mybatis第一步:获取SqlSession对象
*/
static {
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
* SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
* 此方法用于获取SqlSession
*
* @return
*/
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
实体类
package com.bnzr.pojo;
public class User {
private int id;
private String name;
private String pwd;
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public User() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
Dao接口
package com.bnzr.dao;
import com.bnzr.pojo.User;
import java.util.List;
public interface UserDao {
List<User> getUserList();
}
接口实现
<mapper namespace="com.bnzr.dao.UserDao">
<select id="getUserList" resultType="com.bnzr.pojo.User">
select * from `user`
select>
mapper>
package com.bnzr.dao;
import com.bnzr.pojo.User;
import com.bnzr.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
//1.获得sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行sql
//方式一:getMapper()
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
for (User user : userList) {
System.out.println(user);
}
//关闭SqlSession
sqlSession.close();
}
}
namespace中的包名要和Dao/mapper接口包名一致
选择,查询语句;
编写接口
//根据id查询用户
User getUserById(int id);
编写对应的mapper中的sql语句
<select id="getUserById" resultType="com.bnzr.pojo.User" parameterType="int">
select * from mybatis.user where id = #{id};
select>
测试
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userById = mapper.getUserById(1);
System.out.println(userById.toString());
}
编写接口
/**
* 添加用户
* @param user
* @return
*/
int addUser(User user);
编写对应的mapper中的sql语句
<insert id="addUser" parameterType="com.bnzr.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, "甲四", "123456"));
if(res>0){
//增删改需要提交事务
sqlSession.commit();
}else {
//失败回滚
sqlSession.rollback();
}
sqlSession.close();
}
编写接口
/**
* 修改用户
* @param user
* @return
*/
int updateUser(User user);
编写对应的mapper中的sql语句
<update id="updateUser" parameterType="com.bnzr.pojo.User">
update 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, "已四", "666666"));
if(res>0){
//增删改需要提交事务
sqlSession.commit();
}else {
//失败回滚
sqlSession.rollback();
}
sqlSession.close();
}
编写接口
/**
* 删除用户
* @param id
* @return
*/
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){
//增删改需要提交事务
sqlSession.commit();
}else {
//失败回滚
sqlSession.rollback();
}
sqlSession.close();
}
*注意点*:
编写接口
/**
* 添加用户
* 传值使用Map
* @param map
* @return
*/
int addUserMap(Map<String,Object> map);
编写对应的mapper中的sql语句
<insert id="addUserMap" parameterType="map">
insert into mybatis.user (id, name, pwd)
values (#{userid}, #{username}, #{password});
insert>
测试
@Test
public void addUserMap(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("userid",6);
map.put("username","心底");
map.put("password","888666");
int res = mapper.addUserMap(map);
if(res>0){
//增删改需要提交事务
sqlSession.commit();
}else {
//失败回滚
sqlSession.rollback();
}
sqlSession.close();
}
Map传递参数,直接在sql中去除key即可!【parameterType=”map”】
对象传递参数,直接在sql中取对象的属性即可【parameterType=”Object”】
只有一个基本数据类型参数的情况下,可以直接在sql中取到,不用写parameterType
Mybatis 可以配置成适应多套环境
尽管可以配置多套环境,但是每个SqlSessionFactory实例只能选择一种环境
学会配置多套环境!
Mybatis默认的事务管理器就是JDBC,连接池POOLED
我们可以通过properties属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties】
编写一个配置文件
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding-utf8&useSSL=true
username=root
password=root
在核心配置文件中引入
<configuration>
<properties resource="db.properties">
properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/bnzr/dao/UserMapper.xml"/>
mappers>
configuration>
properties属性也可以进行属性设置如:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
properties>
读取顺序 先进性内部属性读取,再进行外部文件读取。如果两个属性名一致会进行覆盖。
类型别名可为 Java 类型设置一个缩写名字。
它仅用于 XML 配置,意在降低冗余的全限定类名书写。
<typeAliases>
<typeAlias type="com.bnzr.dao.User" alias="User">typeAlias>
typeAliases>
也可以指定一个包名,Mybatis会在包名下面搜索需要的Java Bean,比如:
扫描实体类的包,它的默认别名就为这个类的类名,首字母小写
<configuration>
<properties resource="db.properties">
properties>
<typeAliases>
<package name="com.bnzr.pojo"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/bnzr/dao/UserMapper.xml"/>
mappers>
configuration>
xml进行简化
<mapper namespace="com.bnzr.dao.UserMapper">
<select id="getUserList" resultType="user">
select *
from `user`
select>
<select id="getUserById" resultType="user" parameterType="int">
select *
from mybatis.user
where id = #{id};
select>
<insert id="addUser" parameterType="user">
insert into mybatis.user (id, name, pwd)
values (#{id}, #{name}, #{pwd});
insert>
<update id="updateUser" parameterType="user">
update USER
set name = #{name},
pwd=#{pwd}
where id = #{id};
update>
<delete id="deleteUser" parameterType="int">
delete
from mybatis.user
where id = #{id};
delete>
mapper>
在实体类比较少的情况,使用第一种
如果实体类非常多,使用第二种
第一种可以DIY自定义,第二种不行,如果非要取别名,需要使用ibatis的注解功能@Alias
import org.apache.ibatis.type.Alias;
@Alias("test")
public class User {
private int id;
private String name;
private String pwd;}
方式一:使用相对于类路径的资源引用
<mappers>
<mapper resource="com/bnzr/dao/UserMapper.xml"/>
mappers>
方式二:使用映射器接口实现类的完全限定类名
<mappers>
<mapper class="com.xia.dao.UserMapper"/>
mappers>
方式三:将包内的映射器接口实现全部注册为映射器
<mappers>
<package name="com.xia.dao"/>
mappers>
注意点:使用方法二和方法三
生命周期,和作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
这里的每个Mapper,就代表一个具体的业务!
数据库字段名与实体类属性名不对应。
解决方法一:取别名
<select id="getUserById" resultType="user" parameterType="int">
select id,name,pwd as password
from mybatis.user
where id = #{id};
select>
结果:
1张三123456
解决方法二:结果集映射
<resultMap id="UserMap" type="user">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
resultMap>
<select id="getUserById" resultMap="UserMap" parameterType="int">
select *
from mybatis.user
where id = #{id};
select>
如果一个数据库操作,出现了异常,我们需要排错,日志就是最好的助手
曾经:sout,debug
现在:日志工厂!
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J(deprecated since 3.5.9) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
在MyBatis中具体使用哪一个日志实现,在设置中设定。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
全文件
<configuration>
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<typeAliases>
<package name="com.bnzr.pojo"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/bnzr/dao/UserMapper.xml"/>
mappers>
configuration>
什么是Log4j?
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
### 设置###
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 = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=D://logs/error.log ###
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File = ./log/bnzr.log
log4j.appender.file.MaxFileSize = 10mb
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=D://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =D://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %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
<settings>
<setting name="logImpl" value="LOG4J"/>
settings>
import org.apache.log4j.Logger;
static Logger logger = Logger.getLogger(UserDaoTest.class);
logger.info("info:进入了testLog4j");
logger.debug("debug:进入了testLog4j");
logger.error("error:进入了testLog4j");
测试
import org.apache.log4j.Logger;
import org.junit.Test;
public class UserDaoTest {
static Logger logger = Logger.getLogger(UserDaoTest.class);
@Test
public void testlog(){
logger.info("info: 测试");
logger.debug("debug:测试");
logger.error("error:测试");
}
}
--只有一个参数是表示 从0开始查询n个
select * from user limit 2;
--从序号1行开始,查询两个
select * from user limit 1,2;
使用limit实现分页
/**
* 分页查询
* @param map
* @return
*/
List<User> getUserByLimit(Map<String, Integer> map);
<resultMap id="UserMap" type="user">
<result column="pwd" property="password"/>
resultMap>
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from `user` limit #{startIndex} ,#{pageSize}
select>
@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",0);
map.put("pageSize",2);
List<User> userByLimit = mapper.getUserByLimit(map);
for (User user : userByLimit) {
System.out.println(user.toString());
}
sqlSession.close();
}
不再使用sql实现分页
/**
* 分页查询RowBounds
* @return
*/
List<User> getUserByRowBounds();
<select id="getUserByRowBounds" resultMap="UserMap">
select * from `user`
select>
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//RowBounds实现
RowBounds rowBounds = new RowBounds(1, 2);
List<User> userlist = sqlSession.selectList("com.bnzr.dao.UserMapper.getUserByRowBounds",null,rowBounds);
for (User user : userlist) {
System.out.println(user.toString());
}
sqlSession.close();
}
关于接口的理解
三个面向区别
package com.bnzr.dao;
import com.bnzr.pojo.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
List<User> getUser();
}
<configuration>
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<typeAliases>
<package name="com.bnzr.pojo"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper class="com.bnzr.dao.UserMapper"/>
mappers>
configuration>
import com.bnzr.dao.UserMapper;
import com.bnzr.pojo.User;
import com.bnzr.untils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserMapperTest {
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUser();
for (User user : users) {
System.out.println(user.toString());
}
sqlSession.close();
}
}
本质:反射机制实现
底层:动态代理
/**
* 有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
* SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
* 此方法用于获取SqlSession
*
* @return
*/
public static SqlSession getSqlSession() {
//参数设置为true,开启自动提交事务
return sqlSessionFactory.openSession(true);
}
package com.bnzr.dao;
import com.bnzr.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
List<User> getUser();
//方法存在多个参数,所有参数前面必须加上@param注解
@Select("select * from user where id = #{id}")
User getUserBuId(@Param("id") int id);
@Insert("insert into user (id,name,pwd) values(#{id},#{name},#{pwd})")
int addUser (User user);
@Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
int updateUser(User user);
@Delete("delete from user where id=#{uid}")
int deleteUser(@Param("uid") int id);
}
import com.bnzr.dao.UserMapper;
import com.bnzr.pojo.User;
import com.bnzr.untils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserMapperTest {
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUser();
for (User user : users) {
System.out.println(user.toString());
}
sqlSession.close();
}
@Test
public void getUserBuIdTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userBuId = mapper.getUserBuId(1);
System.out.println(userBuId);
sqlSession.close();
}
@Test
public void addUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(4,"甲四","666666"));
sqlSession.close();
}
@Test
public void updateUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(4,"甲四","888888"));
sqlSession.close();
}
@Test
public void deleteUserTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(4);
sqlSession.close();
}
}
#{}这种方式SQL语句是经过预编译的,会把#{}中间的参数转义成字符串。
用 传 入 数 据 直 接 显 示 在 生 成 的 s q l 中 , {}传入数据直接显示在生成的sql中, 传入数据直接显示在生成的sql中,{}方式无法防止sql注入。
$是直接进行拼接,会引发sql注入,不安全,#不会
官网地址:https://projectlombok.org/
ProjectLombok是一个java库,可以自动插入编辑器和构建工具,提高java的性能。永远不要再编写另一个getter或equals方法,使用一个注释,您的类就有了一个功能齐全的生成器,自动化了日志变量,等等。
使用步骤:
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.22version>
<scope>providedscope>
dependency>
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system
Code inspections
Refactoring actions (lombok and delombok)
@Data:无参构造,get,set,toString,equals,hashcode方法
@NoArgsConstructor:无参构造
@AllArgsConstructor:有参构造
CREATE TABLE `teacher`(
`id` INT(10) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO teacher (`id`,`name`)VALUES(1,'秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY(`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO student (`id`,`name`,`tid`)VALUES('1','小明','1');
INSERT INTO student (`id`,`name`,`tid`)VALUES('2','小红','1');
INSERT INTO student (`id`,`name`,`tid`)VALUES('3','小张','1');
INSERT INTO student (`id`,`name`,`tid`)VALUES('4','小李','1');
INSERT INTO student (`id`,`name`,`tid`)VALUES('5','小王','1');
想要查询学生并且携带老师信息
pojo
Teacher
package com.bnzr.pojo;
public class Teacher {
private int id;
private String name;
public Teacher() {
}
public Teacher(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Studemt
package com.bnzr.pojo;
public class Student {
private int id;
private String name;
//学生关联一个老师
private Teacher teacher;
public Student() {
}
public Student(int id, String name, Teacher teacher) {
this.id = id;
this.name = name;
this.teacher = teacher;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", teacher=" + teacher +
'}';
}
}
StudentMapper
package com.bnzr.dao;
import com.bnzr.pojo.Student;
import java.util.List;
public interface StudentMapper {
public List<Student> getStudent();
}
方式一:按照查询嵌套处理
本质其实就是一个子查询
<mapper namespace="com.bnzr.dao.StudentMapper">
<resultMap id="studentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
resultMap>
<select id="getStudent" resultMap="studentTeacher">
select * from student;
select>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id=#{id};
select>
mapper>
方式二:按照结果嵌套查询
本质其实就是一个联表查询
<select id="getStudentTwo" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname ,t.id tid from student s,teacher t where s.tid=t.id;
select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
<result property="id" column="tid"/>
association>
resultMap>
测试
@Test
public void testStudent(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = studentMapper.getStudent();
for (Student student : studentList) {
System.out.println(student);
}
sqlSession.close();
}
想要查询老师并且携带学生信息
pojo
package com.bnzr.pojo;
import java.util.List;
public class Teacher {
private int id;
private String name;
//老师拥有多个学生
private List<Student> studentList;
public Teacher() {
}
public Teacher(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
", studentList=" + studentList +
'}';
}
}
TeacherMapper
package com.bnzr.dao;
import com.bnzr.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface TeacherMapper {
/**
* 获取指定老师
* @param id
* @return
*/
Teacher getTeacherByid(@Param("tid") int id);
/**
* 获取指定老师
* @param id
* @return
*/
Teacher getTeacherByidTwo(@Param("tid") int id);
}
按照结果嵌套查询
<resultMap id="TeacherStudent" type="teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="studentList" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
collection>
resultMap>
<select id="getTeacherByid" resultMap="TeacherStudent">
select s.id sid, s.name sname, t.name tname, t.id tid
from student s,
teacher t
where s.tid = t.id and t.id = #{tid};
select>
按照查询嵌套处理
<select id="getTeacherByidTwo" resultMap="TeacherStudent2">
select *
from teacher
where id = #{tid};
select>
<resultMap id="TeacherStudent2" type="teacher">
<result property="id" column="id"/>
<collection property="studentList" javaType="ArrayList" ofType="student" column="id" select="studentByid"/>
resultMap>
<select id="studentByid" resultType="student">
select *
from student
where tid = #{tid};
select>
测试
@Test
public void testGetTeacherByid(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacherByid = teacherMapper.getTeacherByid(1);
System.out.println(teacherByid);
sqlSession.close();
}
注意点:
动态SQL就是指根据不同的条件生成不同的SQL语句
动态SQL 元素和JSTL 或基于类似XML 的文本处理器相似。在Mybatis 之前的版本中,有很多元素需要花时间了解。Mybatis3 大大精简了元素种类,现在只需学习原来一半的元素便可。Mybtis 采用功能强大的基于OGNL的表达式来淘汰其它大部分元素。
if
choose(when, otherwise)
trim(where, set)
foreach
SQL
CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id' PRIMARY KEY,
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
) ENGINE=INNODB DEFAULT CHARSET=utf8
导包
编写配置文件
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
<configuration>
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
<typeAliases>
<package name="com.bnzr.pojo"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper class="com.bnzr.dao.BlogMapper"/>
mappers>
configuration>
编写工具类
IDUtils
package com.bnzr.untils;
import org.junit.Test;
import java.util.UUID;
/**
* 生成UUID工具类
*/
public class IDUtils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
@Test
public void test(){
System.out.println(IDUtils.getId());
}
}
MybatisUtils
package com.bnzr.untils;
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 MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
/**
* 使用Mybatis第一步:获取SqlSession对象
*/
static {
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
* SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
* 此方法用于获取SqlSession
*
* @return
*/
public static SqlSession getSqlSession() {
//参数设置为true,开启自动提交事务
return sqlSessionFactory.openSession(true);
}
}
编写实体类
package com.bnzr.dao;
import lombok.Data;
import java.util.Date;
@Data
public class Blog {
private int id;
private String title;
private String author;
private Date createTime;
private int views;
}
编写实体类对应Mapper接口和Mapper.xml文件
if标签进行判断
BlogMapper.xml
<select id="queryBlogIF" parameterType="map" resultType="blog">
select *
from blog where 1=1
<if test="title!=null">
and title=#{title}
if>
<if test="author!=null">
and author=#{author}
if>
;
select>
test
@Test
public void queryBlogIFTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap<Object, Object> map = new HashMap<>();
map.put("title","疯狂的卷");
map.put("author","bnzr");
List<Blog> blogs = mapper.queryBlogIF(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。
当满足一个when时就不继续向下走了,当都不满足时才会走otherwise
BlogMapper.xml
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select *
from blog
<where>
<choose>
<when test="title!=null">
and title=#{title}
when>
<when test="author!=null">
and author=#{author}
when>
<otherwise>
and views=#{views}
otherwise>
choose>
where>
;
select>
test
@Test
public void queryBlogChooseTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap<Object, Object> map = new HashMap<>();
map.put("title","简单");
// map.put("author","bnzr");
map.put("views",666);
List<Blog> blogs = mapper.queryBlogChoose(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<select id="queryBlogIF" parameterType="map" resultType="blog">
select *
from blog
<where>
<if test="title!=null">
and title=#{title}
if>
<if test="author!=null">
and author=#{author}
if>
where>
;
select>
set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。
<update id="updateBlog" parameterType="map" >
update blog
<set>
<if test="author!=null">
author=#{author},
if>
<if test="title!=null">
title=#{title},
if>
<if test="views!=null">
views=#{views},
if>
set>
where id = #{id};
update>
有时候,我们可能会将一些功能的部分抽取出来,方便复用。
使用SQL标签抽取公共的部分
<sql id="if-title-author">
<if test="title!=null">
and title=#{title}
if>
<if test="author!=null">
and author=#{author}
if>
sql>
在需要使用的地方使用include标签引用即可
<select id="queryBlogIF" parameterType="map" resultType="blog">
select *
from blog
<where>
<include refid="if-title-author">include>
where>
;
select>
注意事项:
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。
BlogMapper.xml
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="(" close=")" separator="or">
id=#{id}
foreach>
where>
select>
test
@Test
public void queryBlogForeachTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
ArrayList<String> idsList = new ArrayList<>();
idsList.add("01c2a405fb8b41f6b637c61b66f4bbc3");
idsList.add("8106d640c1a244b28ea0dcc8f7dbfd72");
HashMap<Object, Object> map = new HashMap<>();
map.put("ids",idsList);
List<Blog> blogs = blogMapper.queryBlogForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式去排列组合就可以了
测试步骤:
缓存失效情况:
小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段!一级缓存相当于一个Map。
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
在要使用二级缓存的Mapper中开启二级缓存
<mapper namespace="com.bnzr.dao.BlogMapper">
<cache/>
mapper>
这些属性可以通过 cache 元素的属性来修改。比如:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
可用的清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。默认的清除策略是 LRU。
flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
PS:
问题:如果发现实体类序列化报错
Caused by:java.io.NotSerializableException:com.bnzr.pojo.Blog
解决:继承Serializable进行序列化
public class Blog implements Serializable
问题:如果方法想要关闭缓存
解决:对查询添加useCache="false"属性
<select id="queryBlogIF" parameterType="map" resultType="blog" useCache="false">
小结:
先在二级缓存中查找,如果没有再向一级缓存查找,如果没有在查数据库。
优先级:二级缓存 》一级缓存 》查数据库
。缓存可以极大的提升查询效率。
测试步骤:
缓存失效情况:
小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段!一级缓存相当于一个Map。
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
在要使用二级缓存的Mapper中开启二级缓存
<mapper namespace="com.bnzr.dao.BlogMapper">
<cache/>
mapper>
这些属性可以通过 cache 元素的属性来修改。比如:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
可用的清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。默认的清除策略是 LRU。
flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
PS:
问题:如果发现实体类序列化报错
Caused by:java.io.NotSerializableException:com.bnzr.pojo.Blog
解决:继承Serializable进行序列化
public class Blog implements Serializable
问题:如果方法想要关闭缓存
解决:对查询添加useCache="false"属性
<select id="queryBlogIF" parameterType="map" resultType="blog" useCache="false">
小结:
先在二级缓存中查找,如果没有再向一级缓存查找,如果没有在查数据库。
优先级:二级缓存 》一级缓存 》查数据库