目录
1.概念:
2.使用MyBatis的流程
2.1.导入Mysql和MyBatis所依赖的jar包(中途也会根据需要导入其他jar包)
2.2.在resources中创建mybatis.xml配置文件(内容复制粘贴即可)
2.3.创建数据库和表并添加内容。
2.4.创建实体类
2.5.在resources中创建mybatis和数据库的映射文件(复制即可)
2.6将映射文件注册到配置文件中
2.7测试Mybatis
3.使用mybatis完成对数据库的crud(增删改查)
3.1在映射文件中写sql语句
3.2测试类
4.优化MaBatis
4.1.为实体类起别名
4.2.添加sql日志
5.企业开发模式
5.1.创建一个dao接口并定义自己需要的方法(是接口不是类)。
5.2.创建并编写映射文件
5.3测试
6.传递多个参数的方法
6.1.方式一
6.2.方式二
7.添加时返回递增的主键值
8.解决表的字段名与实体类的属性名不一致的情况
8.1.方式一:为查询的列起别名,而别名和属性名一致。
8.2.方式二:使用resultMap完成列和属性之间的映射关系。
9.动态sql
9.1.什么时动态sql
9.2.动态sql的标签有哪些
9.3.if标签——单条件判断
9.4.choose标签——多条件分支判断
9.5.where标签(辅助标签)
9.6.set标签
9.7.foreach标签
9.8.sql片段
10.mybatis映射文件处理特殊字符的方法
10.1使用转义符
10.2.使用
11.mybatis完成模糊查询
11.1使用字符串拼接完成
11.2.使用${}
12.连表查询
13.分页查询(pageHelper)
13.1.回顾分页的sql语句:
13.2.导入pagehelper 依赖的jar 包
13.3.mybatis中设置pageHelper的拦截器
13.4.测试并使用pagehelper
13.5.pagehelper的作用:
13.6.pagehelper的原理
14.mybatis的代码生成器——generator
14.1.作用
14.2.使用流程
15.mybatis的缓存
15.1.缓存的好处
15.2.什么样的数据适合/不适合放入缓存中
15.3.mybatis的缓存有两种
15.4.演示一级缓存
15.4.1.测试重新开启一个session时一级缓存是否有效
15.5.演示二级缓存
MyBatis 是一款优秀的持久层Dao框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Java实体类)映射成数据库中的记录.
使用MyBatis的好处:可以简化jdbc的操作以及占位符赋值以及查询结果集的封装。
4.0.0
com.pgx
mybatis03
1.0-SNAPSHOT
8
8
mysql
mysql-connector-java
8.0.22
org.mybatis
mybatis
3.4.6
log4j
log4j
1.2.17
org.projectlombok
lombok
1.18.24
junit
junit
4.12
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`realname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES (1, 'admin', '管理员');
INSERT INTO `tb_user` VALUES (2, 'lm', '黎明');
INSERT INTO `tb_user` VALUES (3, 'ldh', '刘德华');
INSERT INTO `tb_user` VALUES (4, 'zxy', '张学友');
INSERT INTO `tb_user` VALUES (5, 'gfc', '郭富城');
package com.pgx.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//使用lombok插件添加注解生成get,set方法和有参构造,无参构造,以及重写了toString方法
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
protected int id;
protected String username;
protected String password;
}
public class Test01 {
public static void main(String[] args) throws Exception {
//1.读取mybatis配置文件的内容----未来不需要写tomcat 解析配置文件
Reader reader = Resources.getResourceAsReader("mybatis.xml");
//2. 获取SqlSessionFactory对象
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
//3. 获取SqlSession对象----封装了对数据库操作的各种方法
SqlSession session=factory.openSession();
//调用查询一个结果的接口
//String statement, 命名空间.id----指向mybatis配置文件中sql标签中的id
// Object parameter 需要实参(想要查询的id)
User user = session.selectOne("qy151.user.findById", 2);
System.out.println(user);
//4.关闭
session.close();
}
}
insert into tb_user(username,realname) values(#{username},#{realname})
delete from tb_user where userid=#{id}
update tb_user set username=#{username},realname=#{realname} where userid=#{userid}
package com.test;
import com.ykq.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 org.junit.Test;
import java.io.Reader;
import java.util.List;
public class Test01 {
//查询所有
@Test
public void testFindAll()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session=factory.openSession();
List users = session.selectList("qy151.user.findAll");
System.out.println(users);
session.commit();//必须提交
session.close();
}
//修改
@Test
public void testUpdate()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session=factory.openSession();
User user=new User(8,"lm","黎明");
int row = session.update("qy151.user.update", user);
System.out.println(row);
session.commit();//必须提交
session.close();
}
//删除
@Test
public void testDelete()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session=factory.openSession();
int row = session.delete("qy151.user.delete", 1);
System.out.println(row);
session.commit();//必须提交
session.close();
}
//测试添加
@Test
public void testAdd() throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session=factory.openSession();
User user=new User();
// user.setUsername("lmtb");
// user.setRealname("黎明他爸");
int row = session.insert("qy151.user.add", user);
System.out.println(row);
session.commit();//必须提交
session.close();
}
}
作用:在映射文件sql语句查询标签中定义返回类型的时候省略实体类的路径,直接写别名。
//这里的User就是使用了别名
1).导入log4j依赖
log4j
log4j
1.2.17
2).在resources中创建log4j.properties文件(文件名必须是这个,并将下面的代码写进去,复制即可)
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
作用:在控制台打印你的sql语句的操作,便于查看或纠正sql语句错误
思考: 我们之前使用SqlSession封装的一些方法可以完成crud操作,但是SqlSession封装的方法,传递的参数statement, 传递占位符的参数只能传递一个。而且他的方法名称都是固定。而真实在开发环境下我们不使用SqlSession封装的方法,而是习惯自己定义方法,自己调用自己的方法。
步骤:
package com.pgx.dao;
import com.pgx.entity.User;
import java.util.List;
public interface UserDao {
//根据id查询莫一条记录的方法
public User findOne(int id);
//查询所有记录的方法
public List findAll();
//添加记录的方法
public int insert(User user);
//根据id修改记录的方法
public int edit(User user);
//根据id删除记录的方法
public int delete(int id);
}
insert into user values(null,#{username},#{password})
update user set username=#{username},password=#{password} where id=#{id}
delete from user where id=#{id}
注意:
1.这时的namespace命名空间必须时你的Dao所在的位置。
2.标签里的id的值必须时Dao中定义的方法名,当你调用Dao中的方法时它会根据你的命名空间和 标签id判断执行哪一个Sql语句
public class Text {
//测试根据id查询某一条记录
@Test
public void text01()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
//获取相应接口的代理对象
UserDao userdao = session.getMapper(UserDao.class);
//通过该对象调用其中的方法,并根据方法穿参(后面的方法同理)
User user = userdao.findOne(1);
System.out.println(user);
session.close();
}
//测试查询所有记录的方法
@Test
public void text02()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
UserDao userdao = session.getMapper(UserDao.class);
List list = userdao.findAll();
System.out.println(list);
session.close();
}
//测试添加的方法
@Test
public void text03()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
UserDao userdao = session.getMapper(UserDao.class);
User user = new User();
user.setUsername("女枪");
user.setPassword("4800");
int row = userdao.insert(user);
//返回了主键id的值
System.out.println(user);
System.out.println(row);
session.commit();
session.close();
}
//测试修改的方法
@Test
public void text04()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
UserDao userdao = session.getMapper(UserDao.class);
User user = new User(2,"卡沙","6300");
int row = userdao.edit(user);
System.out.println(row);
session.commit();
session.close();
}
//测试删除的方法
@Test
public void text05()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
UserDao userdao = session.getMapper(UserDao.class);
int row = userdao.delete(8);
System.out.println(row);
session.commit();
session.close();
}
}
思考:为什么传递多个参数时不可以直接使用实例类的属性名作为参数?
因为mybatis在我们传递多个参数时,会帮我们将传入的参数名封装成param1,param2..........
方法:
public User login( String username, String password);
sql语句:
方法:
//通过@param为参数起别名,其中的内容就可以直接写在sql里的#{}中
public User login(@Param("username") String username, @Param("password") String password);
sql语句:
insert into user values(null,#{username},#{password})
测试:
select * from 表名 where name=#{name}
//当 name!=null时sql语句为
select * from 表名 where name=#{name}
//当 name=null 时sql语句为
select * from 表名
动态sql的作用:
简而言之就是可以通过一条sql语句设置动态后满足多种查询需求
方法
//如果name不为null则按照name查询 如果为null则查询所有
public List findByCondition(@Param("name")String name,@Param("money") Double money);
sql语句:
两个条件都满足时两个都作为条件进行查询
方法:
//如果name不为null则按照name查询 如果为null则查询所有
public List findByCondition02(@Param("name")String name,@Param("money") Double money);
sql语句:
只会选择满足其中的一个条件作为查询条件,如果都满足,也只会选择第一个满足的条件作为查询条件,如果都不满足 会使用otherwise中的条件作为查询条件。类似与Java中的switch(case,fainly)
可以看到上面sql语句中,存在 where 1=1 ,是用于当条件都不满足时保证sql语句的合法
where标签的作用:可以自动为你添加where关键字,并且可以帮你去除第一个and |or
使用场景:一般配合if标签使用,修改时修改的内容如果输入空,则不会修改原本的内容。该标签可以帮我们生成set关键字,并且可以去除最后一个逗号。
方法:
public int update(User user);
sql:
update tbl_user02
name = #{name},
pwd = #{pwd},
email = #{email},
where id = #{id}
使用场景:批量查询,删除,添加。
9.7.1.查询
方法:
public List findByids(int[] ary);
sql:
9.7.2.删除
方法:
public int batchDelete(int[] ary);
sql:
delete from account where id in
#{id}
9.7.3.添加
方法:
public int saveBatch(List list);
sql:
//批量添加sql语句语法:
insert into account(属性1,属性2) values(值1,值2),(值3,值4),(值5,值6)
insert into account(name,isdeleted) values
(#{acc.name},#{acc.isdeleted})
执行sql语句时,不建议使用 * 作为查找内容,但是将字段都列出来的话又太繁琐,所以我们可以根据需要查找的内容,封装到sql片段中,编写sql语句时直接调用即可。
select * from User where id>1 and id<5
//使用转义符
select * from User where id > 1 and id < 5
方法:
public List findByLike(String name)
通过观察: 发现使用${}实际上是字符串拼接,它不能防止sql注入, 而#{}它是预编译,它可以防止sql注入问题,#{}实际使用的PreparedStatement.
表1(学生表)
表2(班级表)
条件:
根据学生id查询学生信息并携带班级信息。
sql语句:select * from student s join class c on s.cid = c.cid where stu_id = ?
student实体类:
package com.pgx.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer id;
private String name;
private Integer age;
private String sex;
//班级对象作为属性
private Clazz clazz;
}
class实体类:
package com.pgx.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Clazz {
private int cid;
private String cname;
}
创建接口并构造方法:
package com.pgx.dao;
import com.pgx.entity.Student;
import java.util.List;
public interface StudentDao {
Student findAll(int id);
}
在映射文件中实现方法实现方法:
测试:
select * from 表名 where 条件 limit (page-1)*pageSize, pageSize;
page: 当前页码
pageSize: 每页显示的条数。
com.github.pagehelper
pagehelper
5.1.11
会帮我们的sql语句自动添加分页功能,并且获取一些其他信息。
当执行sql语句时不在时直接进到数据库查找,而是先经过拦截器,拦截器会为sql语句拼接上分页查询的部分,然后在进入数据库查询。
可以根据表,帮你生成具体的实体类,操作类(dao),xml映射文件并携带简单的crud的方法和具体实现
1).导入依赖的jar包
org.mybatis.generator
mybatis-generator-core
1.4.0
2).创建generator的配置文件
内容(复制并结合自己进行修改):
3).编写测试类并在该类中使用代码生成器
List warnings = new ArrayList();
boolean overwrite = true;
File configFile = new File("generator.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
减少与数据库的交互,提高效率。
适合:经常查询并且不经常改变的;数据的正确与否对最终结果影响不大的;
不适合:经常改变的数据;数据的正确与否对最终结果影响很大的;---数据安全性要求不高。例如:商品的库存,银行的汇率,股市的牌价;
1).一级缓存:基于SqlSession级别的缓存。默认一级缓存是开启的,不能关闭。
2).二级缓存:基于SqlSessionFactory级别的缓存,它可以做到多个SqlSession共享数据。默认它是关闭。需要手动开启。
@Test
public void text03()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
UserMapper um = session.getMapper(UserMapper.class);
//查询id为2的数据信息,第一次查询缓存无法命中向数据库发送sql语句,把结果放入缓存中
Users user = um.selectByPrimaryKey(2);
System.out.println(user);
//查询id为2的数据信息,第二次查询缓存命中,不会像数据库发送sql语句,结果从缓存中获取
Users user1 = um.selectByPrimaryKey(2);
System.out.println(user1);
session.close();
}
输出结果:
@Test
public void text04()throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
UserMapper um = session.getMapper(UserMapper.class);
Users user = um.selectByPrimaryKey(2);
System.out.println(user);
//重新开启一个session对象并查询同一条信息
SqlSession session1 = factory.openSession();
UserMapper um1 = session1.getMapper(UserMapper.class);
Users user2 = um1.selectByPrimaryKey(2);
System.out.println(user2);
}
输出结果:
结论:一级缓存仍然无效!
1).首先要开启二级缓存
在mybatis.xml文件中配置
2).在映射文件中使用缓存
3).实体类一定要序列化接口(实现Serializable接口)
4).测试二级缓存
@Test
public void test03() throws Exception{
Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsReader);
SqlSession session=factory.openSession();
UsersMapper mapper = session.getMapper(UsersMapper.class);
//第一次查询编号=2的用户信息--缓存不能命中,则向数据库查询-发送sql语句、把查询的结果放入缓存中。
//查询的结果放入一级缓存和二级缓存。 如果二级缓存能命中,第二次查询就不会发送sql语句
Users users = mapper.selectByPrimaryKey(2);
System.out.println(users);
session.close();
//开启新的SqlSession
SqlSession session1=factory.openSession();
UsersMapper mapper1 = session1.getMapper(UsersMapper.class);
Users users1 = mapper1.selectByPrimaryKey(2);
System.out.println(users1);
}
输出结果:
结论:当使用二级缓存时,开启一个新的session对象,查询同一条记录,会从缓存中获取。