框架可以理解为半成品软件,框架做好以后,接下来在它基础上进行开发。
Mybatis是Java中1个半自动化的ORM框架,Mybatis可以解决程序对数据库操作问题。
Mybatis是一款优秀的持久层框架,它底层封装的是JDBC。
Mybatis通过XML描述符/注解,把实体类的对象与存储过程/SQL语句关联起来。
MyBatis是在Apache许可证2.0下分发的自由软件,是iBATIS 3.0的分支版本。
MyBatis是2001年开始开发的,是“internet”和“abtis(篱笆)”两个单词的组合,其目的是想做互联网的篱笆墙,围绕着数据库提供持久化服务的一个框架。
iBATIS在2004年时捐赠给了Apache软件基金会,2010年更名为MyBatis。
1.入门案例
1.1.数据库表
CREATE TABLE USER( uid INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, password VARCHAR(50) NOT NULL, email VARCHAR(50), birthday DATE );
1.2.主配置文件
<?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://192.168.56.18:3306/dbForJava?characterEncoding=utf8"/> <property name="username" value="zhanggen"/> <property name="password" value="123.com"/> </dataSource> </environment> </environments> <mappers> <!-- 导入SQL语句配置文件从src/下一层开始--> <mapper resource="mappers/UserMapper"/> </mappers> </configuration>
1.3.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"> <!-- namespace(名称空间):当前xml配置文件的唯一标识 namespace+id:就可以唯一定位到1条SQL语句 --> <mapper namespace="UserMapper"> <!-- 本质是一条SQL语句,但是需要我们传入1个User对象 id:是一个表示在当下xml配置文件中不能重复,通过ID定位唯一1条SQL语句 --> <insert id="save" parameterType="com.zhanggen.domain.User"> insert into USER values (null,#{name},#{password},#{email},#{birthday}) </insert> </mapper>
1.4.实体类
package com.zhanggen.domain; import java.util.Date; import java.util.Objects; public class User { // /* 基本数据类型int无法表示数据库中的null,只有引用类型没初始化时null uid INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, password VARCHAR(50) NOT NULL, email VARCHAR(50), birthday DATE */ private Integer uid; private String name; private String password; private String email; private Date birthday; //使用java.util.Date类型 public User() { } public User(Integer uid, String name, String password, String email, Date birthday) { this.uid = uid; this.name = name; this.password = password; this.email = email; this.birthday = birthday; } public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } 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; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(uid, user.uid) && Objects.equals(name, user.name) && Objects.equals(password, user.password) && Objects.equals(email, user.email) && Objects.equals(birthday, user.birthday); } @Override public int hashCode() { return Objects.hash(uid, name, password, email, birthday); } }
1.5.测试代码
package com.zhanggen.test; import com.zhanggen.domain.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.IOException; import java.io.InputStream; import java.util.Date; public class UserTest { @Test public void testSave() throws IOException { //1.准备1个对象 User user = new User(); user.setName("张根"); user.setPassword("123"); user.setEmail("13220198866@163.com"); user.setBirthday(new Date()); //2.读取配置文件,将配置文件读取成流 InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml"); //3.创建1个sqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream); //4.获取session SqlSession sqlSession = sqlSessionFactory.openSession();//自动开启事务 //5.使用sqlsesssion完成user对象的保存 /* 拼装出1条完整的SQL语句 参数1:sql语句的位置 参数2:sql语句中需要传入的参数 */ sqlSession.insert("UserMapper.save",user); //6.提交事务 sqlSession.commit(); //7.释放资源 sqlSession.close(); } }
1.6.日志配置
日志配置文件放在src目录下
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.console.layout.ConversionPattern=%5p [%t] - %m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/rzk.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
1.7.API介绍
Resources:将配置文件读取成一个输入流(图纸)
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder(工人):用于创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory(工厂):用于获取SqlSession
生命周期: 项目创建,他就创建;项目停止,他就销毁
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession(工具): 可以操作sql语句
生命周期: 用的时候就创建,用完就销毁
sqlSession.insert("UserMapper.save",user);
二、接口+实现类实现Dao层(传统)
Mybatis是持久层框架,那么我们使用mybatis实现Dao层,让sevice层调用;
1.接口
package com.zhanggen.mapper; import com.zhanggen.domain.User; public interface UserMapper { void save(User user); }
2.实现类
package com.zhanggen.mapper.impl; import com.zhanggen.domain.User; import com.zhanggen.mapper.UserMapper; 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 UserMapperImpl implements UserMapper { @Override public void save(User user) { try { //1.读取配置文件,将配置文件读取成流 InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建1个sqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream); //3.获取session SqlSession sqlSession = sqlSessionFactory.openSession();//自动开启事务 //4.使用sqlsesssion完成user对象的保存 /* 拼装出1条完整的SQL语句 参数1:sql语句的位置 参数2:sql语句中需要传入的参数 */ sqlSession.insert("UserMapper.save", user); //5.提交事务 sqlSession.commit(); //6.释放资源 sqlSession.close(); } catch (IOException e) { e.printStackTrace(); } } }
3.配置(映射)
<?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"> <!-- namespace(名称空间):当前xml配置文件的唯一标识 namespace+id:就可以唯一定位到1条SQL语句 --> <mapper namespace="UserMapper"> <!-- 本质是一条SQL语句,但是需要我们传入1个User对象 id:是一个表示在当下xml配置文件中不能重复,通过ID定位唯一1条SQL语句 --> <insert id="save" parameterType="com.zhanggen.domain.User"> insert into USER values (null,#{name},#{password},#{email},#{birthday}) </insert> </mapper>
4.测试
使用测试方法模拟service层对dao层进行调用进行dao层的功能测试;
package com.zhanggen.test; import com.zhanggen.domain.User; import com.zhanggen.mapper.impl.UserMapperImpl; import org.junit.Test; import java.io.IOException; import java.util.Date; public class MybatisTest { //模拟service层调用dao层对象 @Test public void testSave() throws IOException { //1.准备1个对象 User user = new User(); user.setName("Martin"); user.setPassword("123"); user.setEmail("13220198866@163.com"); user.setBirthday(new Date()); //2.创建dao的对象,调用save()方法 UserMapperImpl userMapper = new UserMapperImpl(); userMapper.save(user); } }
以上的方式每次增加1条SQL都需要创建1个实现类对象,并且还要告诉Mybatis这个SQL的配置信息;
约定大于编程:框架和框架使用者之间,能通过xml配置约定出来的,都可以由框架去实现,无需框架使用者重复编程实现,
通过xml配置,可以让Mybatis框架,帮助我们创建1个接口的实现类对象;
1.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"> <!-- namespace(名称空间):当前xml配置文件的唯一标识 namespace+id:就可以唯一定位到1条SQL语句 --> <mapper namespace="com.zhanggen.mapper.UserMapper"> <!-- 本质是一条SQL语句,但是需要我们传入1个User对象 id:是一个表示在当下xml配置文件中不能重复,通过ID定位唯一1条SQL语句 --> <insert id="save" parameterType="com.zhanggen.mapper.UserMapper"> insert into USER values (null,#{name},#{password},#{email},#{birthday}) </insert> </mapper>
2.约定不满足报错
org.apache.ibatis.binding.BindingException: Type interface com.zhanggen.mapper.UserMapper is not known to the MapperRegistry.
3.测试
package com.zhanggen.test; import com.zhanggen.domain.User; import com.zhanggen.mapper.UserMapper; 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.IOException; import java.io.InputStream; import java.util.Date; public class MybatisTest { //模拟service层调用dao层对象 @Test public void testSave() throws IOException { //1.准备1个对象 User user = new User(); user.setName("Martin"); user.setPassword("123"); user.setEmail("13220198866@163.com"); user.setBirthday(new Date()); //2.创建dao的对象,调用save()方法 // UserMapperImpl userMapper = new UserMapperImpl(); // userMapper.save(user); //2.使用接口代理的方式获取UserMapper接口的实现类对象 //1.读取配置文件,将配置文件读取成流 InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建1个sqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream); //3.获取session SqlSession sqlSession = sqlSessionFactory.openSession();//自动开启事务 //4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.save(user); // sqlSession.commit(); sqlSession.close(); } }
4.增删改案例
至此使用mybatis操作数据库的步骤为接口+映射+测试;
4.1.接口
在接口中声明dao层的操作方法;
package com.zhanggen.mapper; import com.zhanggen.domain.User; public interface UserMapper { void save(User user); void update(User user); void delete(Integer uid); }
4.2.映射
在映射文件中定义接口方法对应的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"> <!-- namespace(名称空间):当前xml配置文件的唯一标识 namespace+id:就可以唯一定位到1条SQL语句 --> <mapper namespace="com.zhanggen.mapper.UserMapper"> <!-- 本质是一条SQL语句,但是需要我们传入1个User对象 id:是一个表示在当下xml配置文件中不能重复,通过ID定位唯一1条SQL语句 --> <insert id="save" parameterType="com.zhanggen.mapper.UserMapper"> insert into USER values (null,#{name},#{password},#{email},#{birthday}); </insert> <update id="update" parameterType="com.zhanggen.mapper.UserMapper"> update USER set name=#{name},password=#{password},email = #{email},birthday = #{birthday} where uid = #{uid}; </update> <update id="delete" parameterType="java.lang.Integer"> delete from USER where uid = #{uid}; </update> </mapper>
4.3.测试
通过Mybatis创建接口的实现类对象,通过实现类对象,调用接口中声明的方法。
package com.zhanggen.test; import com.zhanggen.domain.User; import com.zhanggen.mapper.UserMapper; 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.IOException; import java.io.InputStream; import java.util.Date; public class MybatisTest { //模拟service层调用dao层对象 @Test public void testSave() throws IOException { //1.准备1个对象 User user = new User(); user.setName("Martin"); user.setPassword("123"); user.setEmail("13220198866@163.com"); user.setBirthday(new Date()); //2.创建dao的对象,调用save()方法 // UserMapperImpl userMapper = new UserMapperImpl(); // userMapper.save(user); //2.使用接口代理的方式获取UserMapper接口的实现类对象 //1.读取配置文件,将配置文件读取成流 InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建1个sqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream); //3.获取session SqlSession sqlSession = sqlSessionFactory.openSession();//自动开启事务 //4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.save(user); // sqlSession.commit(); sqlSession.close(); } @Test public void testUpdate() throws IOException { //1.准备1个对象 User user = new User(); user.setUid(11); user.setName("Martin666"); user.setPassword("123"); user.setEmail("13220198866@163.com"); user.setBirthday(new Date()); //2.创建dao的对象,调用save()方法 // UserMapperImpl userMapper = new UserMapperImpl(); // userMapper.save(user); //2.使用接口代理的方式获取UserMapper接口的实现类对象 //1.读取配置文件,将配置文件读取成流 InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建1个sqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream); //3.获取session SqlSession sqlSession = sqlSessionFactory.openSession();//自动开启事务 //4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.update(user); // sqlSession.commit(); sqlSession.close(); } @Test public void testDelete() throws IOException { //1.读取配置文件,将配置文件读取成流 InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建1个sqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream); //3.获取session SqlSession sqlSession = sqlSessionFactory.openSession();//自动开启事务 //4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.delete(11); // sqlSession.commit(); sqlSession.close(); } }
5.抽取工具类
避免每次执行SQL都重复创建sqlSessionFactory。
避免每次执行SQL前都创建SqlSession对象。
避免每次执行完SQL都关闭SqlSession对象。
5.1.工具类
抽取sqlSessionFactory和sqlSession创建过程为工具类
package com.zhanggen.util; 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 MybatisUtil { private static SqlSessionFactory sqlSessionFactory = null; private static SqlSession sqlSession = null; static { try { //1.读取配置文件,将配置文件读取成流 InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建1个sqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { sqlSession = sqlSessionFactory.openSession(); return sqlSession; } public static void commitAndclose() { if (sqlSession != null) { sqlSession.commit(); sqlSession.close(); } } }
5.2.测试工具类
package com.zhanggen.test; import com.zhanggen.domain.User; import com.zhanggen.mapper.UserMapper; import com.zhanggen.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.After; import org.junit.Before; import org.junit.Test; //抽取sqlSessionFactory和sqlSession创建过程为工具类 public class MyBatisUtilTest { private SqlSession sqlSession = null; @Before public void beforTest() { sqlSession = MybatisUtil.getSqlSession(); } @After public void afterTest() { MybatisUtil.commitAndclose(); } @Test public void testSave() { //1.准备1个对象 User user = new User(); user.setUid(16); user.setName("Martin666"); user.setPassword("123"); user.setEmail("13220198866@163.com"); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.save(user); } @Test public void testUpdate() { //1.准备1个对象 User user = new User(); user.setUid(14); user.setName("Martin"); user.setPassword("123"); user.setEmail("13220198866@163.com"); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); sqlSession.getMapper(UserMapper.class); userMapper.update(user); } }
四、Mybatis静态查询
使用Mybatis持久层框架进行数据库查询;
//查询所有 List<User> queryAll();
<!--List<User> queryAll();--> <!-- resultType只写方法返回值类型中的实体类型--> <select id="queryAll" resultType="com.zhanggen.domain.User"> select * from USER; </select>
UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.queryAll(); for (User user : userList) { System.out.println(user); }
2.1.接口
注意resultMap返回的是1个List<对象>而不是List<Map<String,Object>>;
//查询所有(数据库返回的结果集和实体类属性名称不一一对应的情况) List<User> queryAll2();
2.2.映射
- resultMap标签:用于自定义数据库返回的结果集合实体类属性名称的映射规则(手动指定)
- id属性 : 指定当前规则的1个标识,要求唯一,以便调用;
- type属性: 指定数据库返回的结果集要映射到哪个实体类的属性上
- result子标签: 1个result指1条具体的规则,column指定数据库字段名称 property指定实体类属性名称
<resultMap id="userMap" type="com.zhanggen.domain.User"> <result column="uid" property="uid"></result> <result column="name" property="userName"></result> <result column="password" property="password"></result> <result column="email" property="email"></result> <result column="birthday" property="birthday"></result> </resultMap> <!-- select标签通过resultMap="userMap"属性,指定这次查询使用id="userMap"的规则进行结果解析--> <select id="queryAll2" resultMap="userMap"> select uid,name as userName,password,email,birthday from USER; </select>
2.3.测试
@Test public void testQueryAll2() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.queryAll2(); for (User user : userList) { System.out.println(user); } }
可以直接把这1个参数,传给映射文件,在映射配置中使用形参名称接收这1个参数。
//根据主键查询 User queryByID(int id);
List<User> queryAll2();
//根据主键查询 User queryByUid(Integer uid);
<!-- 单条件查询--> <select id="queryByUid" parameterType="java.lang.Integer" resultType="com.zhanggen.domain.User"> select uid,name as userName,password,email,birthday from USER where uid=#{uid}; </select>
@Test public void testQueryByID() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.queryByUid(17); System.out.println(user); }
如果需要通过多个where条件进行数据库查询 ,那么当前接口的方法中就需要包含多个参数。
如何把多个参数,传给映射文件?
List<User> querybyUserAndPassword(@Param("user") String username,@Param("pwd")String password);
<select id="querybyUserAndPassword" resultType="com.zhanggen.domain.User"> <!-- 方法有多个参数方式1 --> <!-- select * from USER where name= #{arg0} and password=#{arg1}; --> <!-- select * from USER where name= #{param1} and password=#{param2}; --> <!-- 方法有多个参数方式2 使用注解 --> select * from USER where name= #{user} and password=#{pwd}; </select>
@Test public void testQuerybyUserAndPassword() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.querybyUserAndPassword("Martin", "123"); for (User user : userList) { System.out.println(user); } }
List<User> querybyUserAndPassword2(User user );
<!-- 方法有多个参数方式3:参数太多,把多参数封装到1个对象中--> <select id="querybyUserAndPassword2" resultType="com.zhanggen.domain.User"> select * from USER where name= #{name} and password=#{password}; </select>
User userParam = new User(); userParam.setUid(17); userParam.setName("Martin"); userParam.setPassword("123"); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.querybyUserAndPassword2(userParam); for (User user : userList) { System.out.println(user); } }
在Mybatis可以通过2种方式进行like模糊匹配查询;
- concat("%",#{name},"%")
- "% ${value}%" 有SQL注入风险;
1.接口
//模糊查询 List<User> queryLikeName(String name);
2.映射
<!-- 模糊查询--> <select id="queryLikeName" resultType="com.zhanggen.domain.User"> select * from USER where name like concat("%",#{name},"%"); </select>
方式2有SQL注入风险;
<select id="queryLikeName1" resultType="com.zhanggen.domain.User"> select * from USER where name like "% ${value}%"; </select>
3.测试
//模糊查询 @Test public void queryLikeName(){ UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.queryLikeName("M"); for (User user : userList) { System.out.println(user); } }
6.查看新增记录主键ID
向数据库新增1条记录之后 , 如何获取到新增记录的主键id呢?
1.接口
//保存 void save(User user);
2.映射
<!-- useGeneratedKeys="true":告诉Mybatis,我要使用刚刚新增记录的主键 keyProperty="uid" :告诉Mybatis,把新增记录的主键 封装到指定属性 --> <insert id="save" useGeneratedKeys="true" keyProperty="uid"> insert into USER values(null,#{name},#{password},#{email},#{birthday}); </insert>
3.测试
User user = new User(); user.setName("张翠山"); user.setPassword("17822"); user.setEmail("wudangshan@163.com"); user.setBirthday(new Date()); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.save(user); //查看新增记录的 uid System.out.println(user.getUid());
7.MyBatis返回List<Map<String,Object>>
如果MyBatis每次查询都需要先在Java中创建1个实体类,然后去MySQL中执行查询操作,MyBatis根据实体类的属性进行数据的灌入实例类的对象;
其实有些查询不需要创建实体类,可以把MyBatis查询到的结果封装到1个List<Map<String, Object>>类型中返回;
7.1.Controller层
//测试返回前端List嵌套map类型数据 @GetMapping("/queryAll") public List<Map<String,Object>> queryAllInList(){ List<Map<String,Object>> res= reviewService.queryAllInList(); return res; } //测试返回前端map类型数据 @GetMapping("/queryOne") public Map<String,Object> selectOne() { Map<String,Object> res= reviewService.queryOneInMap(); return res; } //测试返回前端数字类型数据 @GetMapping("/total") public Long selectNumber() { Long res= reviewService.queryTotal(); return res; }
7.2.Service层
接口
//测试返回List<Map>数据 List<Map<String, Object>> queryAllInList(); //测试返回Map数据 Map<String, Object> queryOneInMap(); //测试返回数字数据 Long queryTotal();
实现类
//测试返回 List<Map>数据 @Override public List<Map<String, Object>> queryAllInList() { List<Map<String, Object>> res = reviewMapper.getListMaping(); return res; } //测试返回 Map数据 @Override public Map<String, Object> queryOneInMap() { Map<String, Object> res = reviewMapper.getMaping(); return res; } //测试返回数字类型数据数据 @Override public Long queryTotal() { Long number= reviewMapper.getTotalNumber(); return number; }
7.3.Mapper层
<!--测试返回 List<Map>数据--> <select id="getListMaping" resultType="java.util.Map"> select * from mybatis_review </select> <!--测试返回Map--> <select id="getMaping" resultType="java.util.Map"> select * from mybatis_review where id=1; </select> <!--测试返回数字数据--> <select id="getTotalNumber" resultType="java.lang.Long"> select count(1) as number from mybatis_review; </select>
五、Mybatis动态查询
类似于Django的Q查询功能,Mybatis也可以根据前端用户输入的搜索条件,在后端动态组装where查询条件;
我们可以在映射配置文件中使用where标签,进行动态条件判断,完成多个where条件的动态组装。
List<User> dynamicQuery1(User user);
映射
<!--if标签--> <select id="dynamicQuery1" resultType="com.zhanggen.domain.User"> select * from USER <where> <if test="name != null and name !=''"> and name=#{name} </if> <if test="email != null and email !=''"> and email=#{email} </if> </where> </select>
测试
User dynamicQueryUser = new User(); dynamicQueryUser.setName("张翠山"); dynamicQueryUser.setEmail("wudangshan@163.com"); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> usersList = userMapper.dynamicQuery1(dynamicQueryUser); System.out.println("--------------------"); for (User user : usersList) { System.out.println(user); } System.out.println("--------------------");
- choose 用于包含多个条件
- when 用于编写某个条件
- otherwise所有的when都判断失败时,进入此分支
接口
<!-- choose标签--> <select id="dynamicQuery2" resultType="com.zhanggen.domain.User"> select * from USER <where> <choose> <when test="name !=null and name !=''"> and name=#{name} </when> <when test="email != null and email !=''"> and email=#{email} </when> <otherwise> and false </otherwise> </choose> </where> </select>
映射
List<User> dynamicQuery2(User user);
测试
//测试 choose when标签 @Test public void dynamicQuery2() { User dynamicQueryUser = new User(); dynamicQueryUser.setName("张翠山"); dynamicQueryUser.setEmail("wudangshan@163.com"); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> usersList = userMapper.dynamicQuery2(dynamicQueryUser); System.out.println("--------------------"); for (User user : usersList) { System.out.println(user); } System.out.println("--------------------"); }
根据主键id找到1条记录 ,把1个实体类对象中不为空的属性更新到1条记录中;
1.接口
//修改:根据主键id,动态更新1个user对象中不为空的属性 void dynamicUpdate(User user);
2.映射
<!-- set标签 --> <update id="dynamicUpdate" parameterType="com.zhanggen.domain.User"> update USER <set> <if test="name != null and name !=''"> name=#{name}, </if> <if test="email != null and email !=''"> email=#{email}, </if> <if test="birthday != null"> birthday=#{birthday}, </if> </set> where uid=#{uid}; </update>
3.测试
// 测试set标签 @Test public void testdynamicUpdate() { User dynamicUpdateUser = new User(); dynamicUpdateUser.setUid(17); dynamicUpdateUser.setName("张韬"); dynamicUpdateUser.setEmail("zhangtao@zhang.com"); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.dynamicUpdate(dynamicUpdateUser); System.out.println("--------------------"); System.out.println(dynamicUpdateUser); System.out.println("--------------------"); }
foreach标签:用于在映射配置文件中,循环遍历接口方法传入的集合/数组/对象参数;
collection属性:collection属性配置和接口方法传入参数的数据类型有关
- 接口方法传入的参数是集合类型 ===== collection
- 接口方法传入的参数是数组类型 ===== array
- 接口方法传入的参数是对象 ===== 对象的属性名称
item属性 :指定临时变量
separator属性 :指定分隔符
open属性 :指定开始字符
close属性 :指定结束字符
1.接口
//根据uids集合( 多个uid )查询 一个对象的集合 List<User> dynamicQueryInList(List<Integer> idList); //根据uids数组( 多个uid )查询 一个对象的集合 List<User> dynamicQueryInList1(Integer[] idList);
2.映射
<!-- foreach标签--> <select id="dynamicQueryInList" resultType="com.zhanggen.domain.User"> <!--循环遍历拼接in中的字符串 (17,19,22)--> select * from USER where uid in <foreach collection="collection" item="item" separator="," open="(" close=")"> #{item} </foreach> </select> <!-- 传入数组参数(Integer[])--> <select id="dynamicQueryInList1" resultType="com.zhanggen.domain.User"> <!--循环遍历拼接in中的字符串 (17,19,22)--> select * from USER where uid in <foreach collection="array" item="item" separator="," open="(" close=")"> #{item} </foreach> </select>
3.测试
// 测试foreach标签传入1个集合参数 @Test public void testDynamicQueryInList() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); ArrayList<Integer> idList = new ArrayList<>(); idList.add(18); idList.add(19); idList.add(22); //传入1个集合参数 List<User> usersList = userMapper.dynamicQueryInList(idList); System.out.println("--------------------"); for (User user : usersList) { System.out.println(user); } System.out.println("--------------------"); } // 测试foreach标签传入数组 @Test public void testDynamicQueryInList1() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); Integer[] idList = new Integer[]{18, 19, 22}; //传入1个数组参数 List<User> usersList = userMapper.dynamicQueryInList1(idList); System.out.println("--------------------"); for (User user : usersList) { System.out.println(user); } System.out.println("--------------------"); }
六、Mybatis主配置文件
1.接口和映射文件在同1个包下
2.Mybatis主配置文件功能
Mybatis主配置文件(SqlMapConfig.xml)功能如下:
- 配置Mybatis的工作环境
- 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> <!-- properties标签:在当xml中导入1个properties配置文件,用于简化xml配置 properties配置文件一定放在src/目录下 --> <properties resource="mybatis.properties"/> <!-- 给映射文件中实体类型起别名别名:建议不使用别名,使用复制粘贴的方式,不容易出错--> <typeAliases> <!-- 方式1:给单个类起别名--> <!-- <typeAlias type="com.zhanggen.domain.User" alias="user"/>--> <!-- 式2:给1个包下的所有类起别命名,默认类名称小写--> <package name="com.zhanggen.domain"></package> </typeAliases> <!-- 指定数据库环境:development环境 还是test环境 --> <environments default="development"> <!--environment:开发(development)环境--> <environment id="development"> <!--事务管理器:管理事务的提交和回滚--> <transactionManager type="JDBC"/> <!-- dataSource:使用数据库连接池,POOLED是mybatis自动的数据库连接池--> <dataSource type="POOLED"> <!-- 配置数据源的连接信息--> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.development.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> <!-- environment:测试(test)环境--> <environment id="test"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 配置test环境下,数据库连接信息--> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="${dbc.test.url}"/> <property name="username" value="test"/> <property name="password" value="183.com"/> </dataSource> </environment> </environments> <!-- 配置主配置文件如何找到映射文件--> <mappers> <!-- 方式1:配置映射文件的目录--> <!--<mapper resource="mapper/UserMapper"/>--> <!--方式2:配置UserMapper接口类名称--> <!-- <mapper class="com.zhanggen.mapper.UserMapper"/>--> <!-- 方式3(推荐):配置UserMapper接口和UserMapper.xml所在的包名--> <package name="com.zhanggen.mapper"></package> </mappers> </configuration>
七、Mybatis注解开发
使用注解其实是对XML配置的一种替代方式,2者实现的功能一致。
1.创建工程
2.注解实现增删改查
使用注解替代映射文件;
2.1.接口+注解
package com.itheima.mapper; import com.itheima.domain.User; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Options; import org.apache.ibatis.annotations.Select; import java.util.List; public interface UserMapper { //增加 @Insert("insert into USER values (null, #{name},#{password},#{email},#{birthday});") //返回主键id @Options(useGeneratedKeys = true, keyProperty = "uid", keyColumn = "uid") void insert(User user); //查询全部 @Select("select * from USER;") List<User> queryAll(); //主键查询 @Select("select * from USER where uid=#{uid};") User queryByid(Integer uid); //删除 @Delete("delete from USER where uid=#{uid};") void deleteByid(Integer uid); //模糊查询 @Select("select * from USER where name like concat('%',#{name},'%')") List<User> queryLikeName(String name); }
2.2.测试
package com.itheima.test; import com.itheima.domain.User; import com.itheima.mapper.UserMapper; import com.itheima.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.Date; import java.util.List; //动态SQL public class MyBatisUtilTest { private SqlSession sqlSession = null; @Before public void beforTest() { sqlSession = MybatisUtil.getSqlSession(); } @After public void afterTest() { MybatisUtil.commitAndclose(); } //新增 @Test public void testInsert() { User user = new User(); // user.setName("张丹枫"); user.setName("张根"); user.setPassword("98jhd1"); user.setEmail("zhangdanfeng@163.com"); user.setBirthday(new Date()); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.insert(user); System.out.println(user); } //查询所有 @Test public void testQueryAll() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.queryAll(); for (User user : userList) { System.out.println(user); } } //主键查询 @Test public void testQueryByid() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.queryByid(18); System.out.println(user); } //根据主键删除 @Test public void testDeleteByid() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.deleteByid(24); } //模糊查询 @Test public void testQueryLikeName() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.queryLikeName("张"); for (User user : userList) { System.out.println(user); } } }
3.结果集映射到实体类
如果数据库返回的结果集字段和实体类的属性名称不一致,可以使用@ResultMap("userMap")注解手动配置映射规则;
3.1.接口+注解
//查询所有1:结果集和实体类属性名称一一对应,自动完成映射。(默认) @Select("select * from USER;") List<User> queryAll(); //查询所有2: 数据库返回的结果集和实体类的属性名称(通过注解手动完成映射) @Results( id = "userMap", //当前结果集映射规则的名称 value = { @Result(column = "uid", property = "uid", id = true), @Result(column = "username", property = "name"), @Result(column = "password", property = "password"), @Result(column = "email", property = "email"), @Result(column = "birthday", property = "birthday") } ) @Select("select uid,name as username,password,email,birthday from USER;") List<User> queryAll1(); //查询所有3: 复用ResultMap(映射规则 @ResultMap("userMap") @Select("select uid,name as username,password,email,birthday from USER;") List<User> queryAll2();
3.2.测试
//查询所有1: 数据库返回的结果集和实体类的属性名称一一对应(默认) @Test public void testQueryAll() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.queryAll(); for (User user : userList) { System.out.println(user); } } // 查询所有2: 数据库返回的结果集和实体类的属性名称(通过注解手动指定) @Test public void testQueryAll1() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.queryAll1(); for (User user : userList) { System.out.println(user); } } //查询所有3: 复用ResultMap(映射规则 @Test public void testQueryAl2() { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.queryAll2(); for (User user : userList) { System.out.println(user); } }
4.注解实现动态SQL
注解中可以使用动态sql么?可以,当然可以。
@Update("<script>" + "update tb_person " + "<set>" + "<if test='name!=null'>" + "name=#{name}," + "</if>" + "<if test='age!=null'>" + "age=#{age}," + "</if>" + "<if test='sex!=null'>" + "sex=#{sex}" + "</if>" + "</set>" + "where id=#{id}" + "</script>") void updatePerson2(Person person)
简直是手撕sql,但凡有一个符号写错了,直接报错,还不如用映射文件呢。
八、Mybatis分页插件(PageHelper)
对数据库中数据进行分页是1个Web应用的核心功能;
后台分页的公式:
Mybatis自带了1个分页插件PageHelper,可以帮助程序员完成分页功能。
1.自实现分页功能
分页的核心其实就是通过limit进行数据库查询, 自己实现分页功能,可以帮我们充分理解分页的原理。
先自己创建1个PageInfo对象并封装数据,之后再更换PageHelper的com.github.pagehelper.PageInfo对象。
1.1.创建项目
1.2.web层
-----------------------------
package com.zhanggen.web.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } // 设置编码 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; request.setCharacterEncoding("utf-8"); filterChain.doFilter(servletRequest, servletResponse); response.setContentType("text/html;charset=UTF-8 "); } @Override public void destroy() { } }
-----------------------------
package com.zhanggen.web.servlet; import com.zhanggen.domain.PageInfo; import com.zhanggen.domain.User; import com.zhanggen.service.UserService; import com.zhanggen.service.impl.UserServiceImpl; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; @WebServlet("/userServlet") public class UserServlet extends HttpServlet { private UserService userService = new UserServiceImpl(); @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //接收action的值 String action = req.getParameter("action"); if ("findAll".equals(action)) { findAll(req, resp); } else if ("findByPage".equals(action)) { findByPage(req, resp); } else { resp.getWriter().write("请求错误"); } } //查询所有不分页 private void findAll(HttpServletRequest req, HttpServletResponse resp) { } // 查询所有分页 private void findByPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.接收页码信息 String pageNumStr = req.getParameter("pageNum"); //前端当前在第几页 String pageSizeStr = req.getParameter("pageSize"); //2.设置默认值 if (pageNumStr == null || "".equals(pageNumStr)) { pageNumStr = "1"; } if (pageSizeStr == null || "".equals(pageSizeStr)) { pageSizeStr = "5"; } //3.参数类型装转换 Integer pageNum = Integer.parseInt(pageNumStr); Integer pageSize = Integer.parseInt(pageSizeStr); //4.调用service层查询 PageInfo<User> pageInfo = userService.queryByPage(pageNum, pageSize); //结果放入request域对象 req.setAttribute("pageInfo", pageInfo); //页码转发到list2.jsp req.getRequestDispatcher("/list2.jsp").forward(req, resp); } }
1.3.service层
--------------------------------------
接口
package com.zhanggen.service; import com.zhanggen.domain.PageInfo; import com.zhanggen.domain.User; public interface UserService { PageInfo<User> queryByPage(Integer pageNum, Integer pageSize); }
实现类
package com.zhanggen.service.impl; import com.zhanggen.domain.PageInfo; import com.zhanggen.domain.User; import com.zhanggen.mapper.UserMapper; import com.zhanggen.service.UserService; import com.zhanggen.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import java.util.List; public class UserServiceImpl implements UserService { @Override public PageInfo<User> queryByPage(Integer pageNum, Integer pageSize) { SqlSession sqlSession = MybatisUtil.getSqlSession(); PageInfo<User> pageInfo = new PageInfo<>(); UserMapper usermapper = sqlSession.getMapper(UserMapper.class); //totalEntry:数据库里的记录一共多少行 Integer totalEntry = usermapper.queryToal(); pageInfo.setTotal(totalEntry); //pages:数据库里一共多少条记录,前端总共需要分成多少页进行显示 Integer pages = totalEntry % pageSize == 0 ? totalEntry / pageSize : (totalEntry / pageSize) + 1; pageInfo.setPages(pages); //startIndex:当前这1页数据在数据库中起始索引位置 Integer startIndex = (pageNum - 1) * pageSize; //Mybatis获取数据库数据 List<User> userList = usermapper.queryAllByPage(startIndex, pageSize); pageInfo.setList(userList); //pageSize:一页包含多少条记录,后端根据前端参数,设置每1页显示多少条记录 pageInfo.setPageSize(pageSize); //pageNum:当前页的页码 pageInfo.setPageNum(pageNum); MybatisUtil.commitAndclose(); return pageInfo; } }
1.4.mapper(dao)层
package com.zhanggen.mapper; import com.zhanggen.domain.User; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; public interface UserMapper { //计算数据库总共多少条记录 @Select("select count(1) from USER;") Integer queryToal(); // 分页查询 @Select("select * from USER limit #{startIndex},#{pageSize};") List<User> queryAllByPage(@Param("startIndex") Integer startIndex,@Param("pageSize") Integer pageSize); }
1.5.domain
自己创建的PageInfo对象。
package com.zhanggen.domain; import java.util.List; public class PageInfo<T> { private Integer total; //总记录条目 private Integer pages; //总页数 private List<T> list; //当前页数据 private Integer pageNum;//当前页码 private Integer pageSize; //控制每页显示5条记录 public PageInfo() { } public PageInfo(Integer total, Integer pages, List<T> list, Integer pageNum, Integer pageSize) { this.total = total; this.pages = pages; this.list = list; this.pageNum = pageNum; this.pageSize = pageSize; } public Integer getTotal() { return total; } public void setTotal(Integer total) { this.total = total; } public Integer getPages() { return pages; } public void setPages(Integer pages) { this.pages = pages; } public List<T> getList() { return list; } public void setList(List<T> list) { this.list = list; } public Integer getPageNum() { return pageNum; } public void setPageNum(Integer pageNum) { this.pageNum = pageNum; } public Integer getPageSize() { return pageSize; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } }
--------------------------
package com.zhanggen.domain; import java.util.Date; import java.util.Objects; public class User { // /* 基本数据类型int无法表示数据库中的null,只有引用类型没初始化时null uid INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, password VARCHAR(50) NOT NULL, email VARCHAR(50), birthday DATE */ private Integer uid; private String name; private String password; private String email; private Date birthday; //使用java.util.Date类型 public User() { } public User(Integer uid, String name, String password, String email, Date birthday) { this.uid = uid; this.name = name; this.password = password; this.email = email; this.birthday = birthday; } public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } 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; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(uid, user.uid) && Objects.equals(name, user.name) && Objects.equals(password, user.password) && Objects.equals(email, user.email) && Objects.equals(birthday, user.birthday); } @Override public int hashCode() { return Objects.hash(uid, name, password, email, birthday); } @Override public String toString() { return "User{" + "uid=" + uid + ", name='" + name + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + ", birthday=" + birthday + '}'; } }
1.6.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> <style> table { margin: 30px auto; text-align: center; } #page td { width: 20px; border: 1px solid gray; } </style> </head> <body> <table border="1" cellpadding="0" cellspacing="0" width="600px"> <tr> <td>编号</td> <td>姓名</td> <td>密码</td> <td>邮箱</td> <td>生日</td> </tr> <c:forEach items="${pageInfo.list}" var="emp"> <tr> <td>${emp.uid }</td> <td>${emp.name }</td> <td>${emp.password }</td> <td>${emp.email }</td> <td>${emp.birthday }</td> </tr> </c:forEach> </table> <table> <tr> <td style="text-align: left">总共检索到${pageInfo.total}条记录,共分${pageInfo.pages}页</td> </tr> </table> <table id="page"> <tr> <c:if test="${pageInfo.pageNum>1}"> <td style="width:50px"> <a href="${pageContext.request.contextPath}/userServlet?action=findByPage&pageNum=${pageInfo.pageNum-1}&pageSize=${pageInfo.pageSize}"> 上一页 </a> </td> </c:if> <c:forEach begin="1" end="${pageInfo.pages}" var="page"> <td> <a href="${pageContext.request.contextPath}/userServlet?action=findByPage&pageNum=${page}&pageSize=${pageInfo.pageSize}"> ${page} </a> </td> </c:forEach> <c:if test="${pageInfo.pageNum<pageInfo.pages}"> <td style="width:50px"> <a href="${pageContext.request.contextPath}/userServlet?action=findByPage&pageNum=${pageInfo.pageNum+1}&pageSize=${pageInfo.pageSize}"> 下一页 </a> </td> </c:if> </tr> </table> </body> </html>
2.PageHelper插件实现分页
理解了分页的原理之后,就完全可以使用分页插件了;
他可以帮助程序员自动构建PageInfo对象,内部实现了分页逻辑,程序员可以直接使用。
官网:
2.1.主配置文件
在Mybatis的主配置文件environments标签上方,加入如下配置
<!-- 添加PageHelper分页插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <property name="autoRuntimeDialect" value="true"/> </plugin> </plugins>
2.2.更换PageHelper内置的PageInfo对象
2.3.PageHelper插件核心原理
执行静态方法:开启PageHelper分页插件,设置拦截器,拦截所有select * from table查询所有的SQL语句,
在进行查询所有SQL语句后面进行SQL拼接,所以select * from table后面要加分号;
package com.zhanggen.service.impl; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.zhanggen.domain.User; import com.zhanggen.mapper.UserMapper; import com.zhanggen.service.UserService; import com.zhanggen.util.MybatisUtil; import org.apache.ibatis.session.SqlSession; import java.util.List; public class UserServiceImpl implements UserService { // @Override // public PageInfo<User> queryByPage(Integer pageNum, Integer pageSize) { // SqlSession sqlSession = MybatisUtil.getSqlSession(); // PageInfo<User> pageInfo = new PageInfo<>(); // UserMapper usermapper = sqlSession.getMapper(UserMapper.class); // //totalEntry:数据库里的记录一共多少行 // Integer totalEntry = usermapper.queryToal(); // pageInfo.setTotal(totalEntry); // //pages:数据库里一共多少条记录,前端总共需要分成多少页进行显示 // Integer pages = totalEntry % pageSize == 0 ? totalEntry / pageSize : (totalEntry / pageSize) + 1; // pageInfo.setPages(pages); // //startIndex:当前这1页数据在数据库中起始索引位置 // Integer startIndex = (pageNum - 1) * pageSize; // //Mybatis获取数据库数据 // List<User> userList = usermapper.queryAllByPage(startIndex, pageSize); // pageInfo.setList(userList); // //pageSize:一页包含多少条记录,后端根据前端参数,设置每1页显示多少条记录 // pageInfo.setPageSize(pageSize); // //pageNum:当前页的页码 // pageInfo.setPageNum(pageNum); // MybatisUtil.commitAndclose(); // return pageInfo; // } @Override public PageInfo<User> queryByPage(Integer pageNum, Integer pageSize) { SqlSession sqlSession = MybatisUtil.getSqlSession(); UserMapper usermapper = sqlSession.getMapper(UserMapper.class); //1.执行静态方法:开启PageHelper分页插件(设置拦截器,拦截所有select * from table查询所有的SQL语句, // 在进行查询所有SQL语句后面进行SQL拼接,所以select * from table后面要加分号;) PageHelper.startPage(pageNum, pageSize); //2.执行查询所有SQL语句 List<User> userList = usermapper.queryAll(); //3.实例化封装1个PageInfo对象 PageInfo<User> pageInfo = new PageInfo<>(userList); //4.是否数据库连接资源 MybatisUtil.commitAndclose(); //5.返回PageInfo对象 return pageInfo; } }
九、MySQL实现业务功能
1.实现增长和累计增量趋势分析
1.1.存储过程生成连续日期表
利用存储过程,生成1张单独的时间表, 避免使用程序生成时间;
-- 存储过程生成连续日期表 DELIMITER $$ DROP PROCEDURE IF EXISTS create_calendar $$ CREATE PROCEDURE create_calendar (s_date DATE, e_date DATE) BEGIN SET @createSql = 'CREATE TABLE IF NOT EXISTS tb_day ( `date` date NOT NULL, UNIQUE KEY `unique_date` (`date`) USING BTREE )ENGINE=InnoDB DEFAULT CHARSET=utf8'; prepare stmt from @createSql; execute stmt; WHILE s_date <= e_date DO INSERT IGNORE INTO tb_day VALUES (DATE(s_date)) ; SET s_date = s_date + INTERVAL 1 DAY ; END WHILE ; END $$ DELIMITER ; CALL create_calendar ('2020-01-01', '2040-12-31');
1.2.mapper层
在mapper层左连接刚刚生成的时间表
# 统计每天新增线索数量,格式化日期 select c.date, ifnull(num, 0) as num from tb_day c left join ( select date_format(create_time, '%Y-%m-%d') as time, count(id) as num from tb_clue where date_format(create_time, '%Y-%m-%d') between '2022-04-21' and '2022-06-25' group by time ) as b on c.date = b.time where c.date between '2022-06-01' and '2022-06-20' order by c.date
1.3.service层
//线索统计 @Override public LineChartVO cluesStatistics(String beginCreateTime, String endCreateTime) { //准备返回给前端的线形图对象 LineChartVO lineChartVO = new LineChartVO(); //1. 查询时间范围内每天线索数量 List<Map<String, Object>> list = reportMpper.cluesStatistics2(beginCreateTime, endCreateTime); //2. 准备y轴2个对象 LineSeriesVO newClues = new LineSeriesVO(); LineSeriesVO totalClues = new LineSeriesVO(); //3. 遍历list,获取到每天的日期和新增数 Long total = 0L; for (Map<String, Object> map : list) { String date = (String) map.get("date"); Long num = (Long) map.get("num"); //3-1 收集日期,设置xAxis lineChartVO.getxAxis().add(date); //3-2 收集新增线索数量 newClues.getData().add(num); //3-3 收集线索总数量 total += num; totalClues.getData().add(total); } //4. 设置y轴中的name newClues.setName("新增线索数量"); totalClues.setName("线索总数量"); //5. 设置y轴集合到返回对象 lineChartVO.getSeries().add(newClues); lineChartVO.getSeries().add(totalClues); return lineChartVO; }