MyBatis是一款优秀的持久层框架,用于简化JDBC的开发
持久层:持久化操作的层,通常指数据访问层(dao),是用来操作数据库的
①包规范:一般取名叫mapper
②接口规范:XxxMapper
①注解
(目录三)
②XML
(目录四)
创建springboot工程,并导入mybatis的起步依赖、mysql的驱动包
步骤:File➜New Project➜Spring Initializr➜按照下面的选,然后一路next即可
①数据以及SQL代码
-- 创建数据库 DROP DATABASE IF EXISTS mybatis_test; CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4; -- 使⽤数据数据 USE mybatis_test; -- 创建表[⽤⼾表] DROP TABLE IF EXISTS userinfo; CREATE TABLE `userinfo` ( `id` INT ( 11 ) NOT NULL AUTO_INCREMENT, `username` VARCHAR ( 127 ) NOT NULL, `password` VARCHAR ( 127 ) NOT NULL, `age` TINYINT ( 4 ) NOT NULL, `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认', `phone` VARCHAR ( 15 ) DEFAULT NULL, `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除', `create_time` DATETIME DEFAULT now(), `update_time` DATETIME DEFAULT now(), PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; -- 添加⽤⼾信息 INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone ) VALUES ( 'admin', 'admin', 18, 1, '18612340001' ); INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone ) VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' ); INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone ) VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' ); INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone ) VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
②在Navicat中创建数据表
①先创建一个model包,里面用来放实体类,然后创建对应的实体类UserInfo
②在UserInfo中完善代码
(注意:实体类的属性名与表中的字段名需要⼀⼀对应)
package com.hlizoo.demo.model; import lombok.Data; import java.util.Date; @Data public class UserInfo { private Integer id; private String username; private String password; private Integer age; private Integer gender; private String phone; private Integer deleteFlag; private Date createTime; private Date updateTime; }
Mybatis中要连接数据库,需要数据库相关参数配置
①URL
②登录名
③密码
④MySQL驱动类
关于MySQL驱动类的注意事项:
(1)如果使用MySQL是5.x之前版本则MySQL驱动类使用的是"com.mysql.jdbc.Driver"
(2)如果使用MySQL是5.x之后版本则MySQL驱动类使用的是“com.mysql.cj.jdbc.Driver”
# 数据库连接配置 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver //用户名和密码根据你的数据库而定 //mybatis_test就是你自己的数据库名,你的可能是别的名
#驱动类名称 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.url= jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false #连接数据库的⽤⼾名 spring.datasource.username=root #连接数据库的密码 spring.datasource.password=root //用户名和密码根据你的数据库而定 //mybatis_test就是你自己的数据库名
表示是MyBatis中的Mapper接口
程序运行时, 框架会自动生成接口的实现类对象(代理对象),并交给Spring的IOC容器管理
与五大注解功能一样;但因为这里用的是MyBatis,所以要用它的注解而不用五大注解
①包规范:一般取名叫mapper
②接口规范:XxxMapper
①创建的包和接口
②UserInfoMapper接口代码
(@Select注解:代表的就是select查询,也就是注解对应方法的具体实现内容)
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper public interface UserInfoMapper { @Select("select * from userinfo") public List
selectAll(); }
1. 在需要测试的Mapper接口中,右键➜Generate➜Test
2. 选择要测试的方法,点击OK
3.编写代码
(记得加@SpringBootTest注解, 加载Spring运行环境)
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.junit.jupiter.api.Assertions.*; //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void selectAll() { List
userInfoList = userInfoMapper.selectAll(); System.out.println(userInfoList); } }
4.运行结果
Mybatis当中我们可以借助日志,查看到sql语句的执行、执行传递的参数以及执行的结果
在配置文件中进行配置即可
①application.properties配置
#指定mybatis输出⽇志的位置, 输出控制台 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
②application.yml配置
# 配置打印 MyBatis⽇志 mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
重新运行程序之后,观察效果
①查询语句
②传递的参数以及类型
③SQL执行结果
为了解决限制字段条件的语句
(比如查询id=4的用户数据,那么id该怎么传?)
两个步骤
①先在注解修饰的方法形参中加入你需要限制条件的字段名
②然后再给注解中查询语句限制条件的字段名加上#{ }
此时传过去的限制条件就是动态的了;比如我想查询id=3的用户数据,那么我就传入参数id为3,如果我突然又想查询id=4的用户数据,那就传入参数id为4,就很方便,动态的输入,而不是写死
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper public interface UserInfoMapper { @Select("select * from userinfo where id=#{id}") List
selectOne(Integer id); }
②UserInfoMapperTest测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.junit.jupiter.api.Assertions.*; //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void selectOne() { //查询id=4的用户数据 List
userInfoList1 = userInfoMapper.selectOne(4); System.out.println(userInfoList1); } }
③运行结果
④比如我突然想查询id=3的用户数据,那么我只需要将参数改成3即可
①如果SQL查询只需要一个参数,那么参数字段名是可以任意的
(但还是建议和参数名保持⼀致,两个是一样最好!!!)
②如果SQL查询需要的参数超过一个,那么参数字段名不可以任意
③通过@Param设置参数的别名,如果使用@Param设置别名, #{...}里面的属性名必须和 @Param设置的⼀样
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper public interface UserInfoMapper { @Select("select * from userinfo where id=#{userid}") List
selectOne2(@Param("userid") Integer id); } package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.junit.jupiter.api.Assertions.*; //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void selectOne2() { List
userInfoList2 = userInfoMapper.selectOne2(1); System.out.println(userInfoList2); } }
两个步骤;使用@Insert注解
①先在@Insert注解修饰的方法形参中加入需要添加的实体类对象
(方法形参传的是对象)
②然后再在@Insert注解中写上insert语句,values后面的参数加上#{}
(这些参数名要与实体类的属性名相一致)
@Insert语句返回的是Integer类型,即返回的是有多少行受影响
①UserInfo实体类的代码
package com.hlizoo.demo.model; import lombok.Data; import java.util.Date; @Data public class UserInfo { private Integer id; private String username; private String password; private Integer age; private Integer gender; private String phone; private Integer deleteFlag; private Date createTime; private Date updateTime; }
②UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper public interface UserInfoMapper { @Insert("insert into userinfo(username,password,age,gender,phone) "+ "values(#{username},#{password},#{age},#{gender},#{phone})") Integer insert(UserInfo userInfo); }
③UserInfoMapperTest测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void insert() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("zhaoliu"); userInfo.setPassword("zhaoliu"); userInfo.setAge(18); userInfo.setGender(0); userInfo.setPhone("123456666"); Integer result = userInfoMapper.insert(userInfo); log.info("inset方法的执行结果:"+result); } }
④观察结果
Insert语句默认返回的是受影响的行数,但有些情况下,数据插插入之后,还需要有后续的关联操作,需要获取到新插入数据的id,即要拿到自增id
在Mapper接口的方法上添加⼀个Options的注解
@Options注解有两个参数
①useGeneratedKeys:是否使用自动生成的key;默认值为false
②keyProperty:将这个自动生成的key赋值给谁;默认是未设置
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserInfoMapper { @Options(useGeneratedKeys = true,keyProperty = "id") @Insert("insert into userinfo(username,password,age,gender,phone) "+ "values(#{username},#{password},#{age},#{gender},#{phone})") Integer insert(UserInfo userInfo); }
②UserInfoMapperTest测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void insert() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("zhaoliu"); userInfo.setPassword("zhaoliu"); userInfo.setAge(18); userInfo.setGender(0); userInfo.setPhone("123456666"); Integer result = userInfoMapper.insert(userInfo); log.info("inset方法的执行结果:"+result); } }
③测试效果
@Insert注解修饰的方法同样可以用@Param进行重命名
如果使用@Param将对象进行重命名,#{}需要使用重命名的对象名字.属性来获取
两个步骤;使用@Delete注解
①先在@Delete注解修饰的方法形参中加入你需要删除哪些限制条件的字段名数据
②然后再给@Delete注解中删除语句限制条件的字段名加上#{ }
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserInfoMapper { @Delete("delete from userinfo where id=#{id}") Integer delete(Integer id); }
②UserInfoMapperTest测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void delete() { userInfoMapper.delete(6); log.info("删除完毕"); } }
③运行结果
两个步骤;使用@Update注解
①先在@Update注解修饰的方法形参中加入你需要修改哪些限制条件的字段名数据
②然后再给@Update注解中修改语句限制条件的字段名加上#{ }
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserInfoMapper { @Update("update usernifo set age=#{age} where id=#{id}") Integer update(UserInfo userInfo); }
②UserInfoMapperTest测试代码
import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void update() { UserInfo userInfo = new UserInfo(); userInfo.setAge(55); userInfo.setId(5); Integer result = userInfoMapper.update(userInfo); if(result>0){ log.info("数据修改成功!"); } } }
③运行结果
两个步骤;使用@Select注解
①先在@Select注解修饰的方法形参中加入你需要修改哪些限制条件的字段名数据
②然后再给@Select注解中修改语句限制条件的字段名加上#{ }
在SQL语句中,给列名起别名,保持别名和实体类属性名一样
原因:结果映射;MyBatis会自动的根据数据库的字段名和Java对象的属性名进行映射;如果名称一样就进行赋值
①比如我现在UserInfo实体类的属性名如下
②那我在@Select注解中的查询语句字段保持跟上述一样
③运行结果
方法:使用@Results和@Result注解完成起别名,实现结果映射
(1)column:列名;表示要给哪一个字段起别名
(数据库字段)
(2)property:表示起的别名叫什么
(java属性字段)
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserInfoMapper { @Results({ @Result(column = "delete_flag",property = "deleteFlag"), @Result(column = "create_time",property = "createTime"), @Result(column = "update_time",property = "updateTime") }) @Select("select * from userinfo") List
selectAll2(); } ②UserInfoMapperTest测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void selectAll2() { List
userInfoList = userInfoMapper.selectAll2(); System.out.println(userInfoList); } } ③运行结果
如果其他SQL,也希望可以复用这个映射关系,可以给这个Results定义一个名称
(好处:避免写了太多的@Results,代码可读性差)
方法
①给@Results加上一个id属性,表示定义一个名称;再加个value
②再在需要复用Results的方法加个@ResultsMapper注解,然后写value属性为定义的名称
方法:使用配置文件;使得这两种方式自动进行映射,而不用进行重命名
(原因:通常数据库列使用蛇形命名法进行命名(下划线分割各个单词),而Java属性⼀般遵循驼峰命名法约定)
①application.yml文件
mybatis: configuration: map-underscore-to-camel-case: true
②application.properties文件
mybatis.configuration.map-underscore-to-camel-case=true
参考《目录二MyBatis入门的(3)数据库配置文件》
classpath后面跟的就是resources里所在的目录
比如下面我放的是mapper,那么我就要在resources目录下创建一个mapper目录
①application.yml文件
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件 mybatis: mapper-locations: classpath:mapper/**Mapper.xml
②application.properties文件
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件 mybatis.mapper-locations=classpath:mapper/**Mapper.xml
注意:XML和注解是可以共存的
如图,创建一个名为UserInfoXMLMapper的接口,然后声明一个方法
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserInfoXMLMapper { List
selectAll(); }
在classpath后面跟的目录底下创建一个XML文件,在这里写XML代码
(建议这个XML文件名字跟你的接口名字是一样的)
比如我的classpath后面是mapper,那我就在mapper目录下添加一个XML文件
注:
指的是你要实现的是哪个接口 ①接口必须是全限定类名
②全限定类名:包+类名
比如我的包是package com.hlizoo.demo.mapper,类名是UserInfoXMLMapper,那么我的mapper namespace如下图所示
代码的实现都在mapper标签里
(1)id:接口定义的方法名
(2)resultType:定义的实体类;实体类也必须是全限定类名
XML代码:
测试代码:
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j @SpringBootTest class UserInfoXMLMapperTest { @Autowired private UserInfoXMLMapper userInfoXMLMapper; @Test void selectAll() { List
userInfoList = userInfoXMLMapper.selectAll(); log.info(userInfoList.toString()); } } 结果:
使用
标签;id依旧是接口定义的方法名
属性声明和注解一样,使用#{ }
除了select查询需要resultType,其他的增删改查只需要写id即可
①UserInfo接口的方法代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserInfoXMLMapper { Integer insert(UserInfo userInfo); }
②UserInfoXMLMapper的xml代码
insert into userinfo(username,password,age,gender,phone) values(#{username},#{password},#{age},#{gender},#{phone})
③UserInfoXMLMapperTest测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j @SpringBootTest class UserInfoXMLMapperTest { @Autowired private UserInfoXMLMapper userInfoXMLMapper; @Test void insert() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("love"); userInfo.setPassword("java"); userInfo.setAge(8); userInfo.setGender(1); userInfo.setPhone("1589666666"); Integer result = userInfoXMLMapper.insert(userInfo); log.info("影响的行数:"+result); } }
④运行结果
在insert标签中设置useGeneratedKeys和keyProperty属性,和注解一模一样
如果在接口方法中形参中对象使用@Param重命名,那么#{}需要使用重命名的名字.属性来获取
和注解一模一样
使用
标签;id依旧是接口定义的方法名
属性声明和注解一样,使用#{ }
除了select查询需要resultType,其他的增删改查只需要写id即可
①UserInfo接口的方法代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserInfoXMLMapper { Integer delete(Integer id); }
②UserInfoXMLMapper的xml代码
delete from userinfo where id=#{id}
③UserInfoXMLMapperTest测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j @SpringBootTest class UserInfoXMLMapperTest { @Autowired private UserInfoXMLMapper userInfoXMLMapper; @Test void delete() { Integer result = userInfoXMLMapper.delete(8); log.info("成功影响的行数:"+result); } }
④运行结果
使用
标签;id依旧是接口定义的方法名
属性声明和注解一样,使用#{ }
除了select查询需要resultType,其他的增删改查只需要写id即可
①UserInfo接口的方法代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserInfoXMLMapper { Integer update(UserInfo userInfo); }
②UserInfoXMLMapper的xml代码
update userinfo set gendar=#{} where id=#{id}
③UserInfoXMLMapperTest测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j @SpringBootTest class UserInfoXMLMapperTest { @Autowired private UserInfoXMLMapper userInfoXMLMapper; @Test void update() { UserInfo userInfo = new UserInfo(); userInfo.setGender(555); userInfo.setId(9); userInfoXMLMapper.update(userInfo); } }
④运行结果
使用标签;id是接口定义的方法名,resultType是实体类的全限定类名
属性声明和注解一样,使用#{ }
和注解的三种方法一样,还是比较推荐驼峰命名
(只有和第二种的略微不一样,下面我们详细说第二种)
①创建一个数据库mybatis_test,在库中创建一张用户表,一张文章表
(用户表的id对应文章表的uid)
②创建一个model包,包中创建两个实体类,一个表示用户实体类,一个表示文章实体类
①SQL代码
-- 创建数据库 DROP DATABASE IF EXISTS mybatis_test; CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4; -- 使⽤数据数据 USE mybatis_test; -- 创建表[⽤⼾表] DROP TABLE IF EXISTS userinfo; CREATE TABLE `userinfo` ( `id` INT ( 11 ) NOT NULL AUTO_INCREMENT, `username` VARCHAR ( 127 ) NOT NULL, `password` VARCHAR ( 127 ) NOT NULL, `age` TINYINT ( 4 ) NOT NULL, `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认', `phone` VARCHAR ( 15 ) DEFAULT NULL, `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除', `create_time` DATETIME DEFAULT now(), `update_time` DATETIME DEFAULT now(), PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; -- 添加⽤⼾信息 INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone ) VALUES ( 'admin', 'admin', 18, 1, '18612340001' ); INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone ) VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' ); INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone ) VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' ); INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone ) VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
②实体类
package com.hlizoo.demo.model; import lombok.Data; import java.util.Date; @Data public class UserInfo { private Integer id; private String username; private String password; private Integer age; private Integer gender; private String phone; private Integer deleteFlag; private Date createTime; private Date updateTime; }
①SQL代码
-- 创建文章表 DROP TABLE IF EXISTS articleinfo; CREATE TABLE articleinfo ( id INT PRIMARY KEY auto_increment, title VARCHAR ( 100 ) NOT NULL, content TEXT NOT NULL, uid INT NOT NULL, delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除', create_time DATETIME DEFAULT now(), update_time DATETIME DEFAULT now() ) DEFAULT charset 'utf8mb4'; -- 插入测试数据 INSERT INTO articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1);
②实体类
package com.hlizoo.demo.model; import lombok.Data; import java.util.Date; @Data public class ArticleInfo { private Integer id; private String title; private String content; private Integer uid; private Integer deleteFlag; private Date createTime; private Date updateTime; }
SQL语句:
select ta.*,tb.username,tb.age from articleinfo ta left join userinfo tb on ta.uid=tb.id where ta.uid=1;
关键点:和普通查询一样,只不过需要在你映射对象的实体类加多几个属性
①先在mapper目录下创建一个ArticleInfoMapper接口
②在ArticleInfoMapper接口中实现对应的方法
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.ArticleInfo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface ArticleInfoMapper { @Select("select ta.*,tb.username,tb.age from articleinfo ta left join userinfo tb on ta.uid=tb.id where ta.uid=1") ArticleInfo selectArticleAndUserById(Integer articleId); }
③在ArticleInfoMapperTest完成测试代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.ArticleInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @Slf4j @SpringBootTest class ArticleInfoMapperTest { @Autowired private ArticleInfoMapper articleInfoMapper; @Test void selectArticleAndUserById() { ArticleInfo articleInfo = articleInfoMapper.selectArticleAndUserById(1); log.info(articleInfo.toString()); } }
④补充ArticleInfo实体类信息
(因为select查询语句还用到username和age,如果ArticleInfo没有写就无法显示)
package com.hlizoo.demo.model; import lombok.Data; import java.util.Date; @Data public class ArticleInfo { private Integer id; private String title; private String content; private Integer uid; private Integer deleteFlag; private Date createTime; private Date updateTime; //补充用户相关信息 private String username; private Integer age; }
⑤运行结果
观察日志可得:id的值是使用?进行占位的
①#{username}没有使用拼接引号' '
②观察日志可得:username的值是使用?进行占位的
观察日志可得:id的值是直接拼接在字符串当中
①'${username}'必须要使用拼接引号' '
②观察日志可得:username的值是直接拼接在字符串当中
#{} 和 ${}都是为了去获取变量的值
①#{}:使用的是预编译SQL
(用?作为占用符,提前对SQL进行编译, 然后把参数填充到SQL语句中)
②${}:使用的是即时SQL
(直接把变量拼接上去,一起对SQL进行编译)
①#{}:如果参数类型为String,会自动的加上引号' '
②${}:如果参数类型为String,必须手动加上引号' '
①#{}:属于预编译SQL;性能比较高
②${}:属于即时SQL;性能比较低
①#{}:不存在SQL注入的安全漏洞问题
②${}:存在SQL注入的安全漏洞问题
(由于${}是手动添加引号,在用户输⼊参数时,在参数中添加⼀些 SQL关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击)
例如下图这个代码,当你的查询条件加入这个,就会查询到所有的数据
①#{}:实际开发中,能使用#{}就尽量使用
②${}:用于排序查询和模糊查询;除了这两个,其他查询如果用${},必须考虑SQL注入安全问题
当使用到SQL语句排序的时候,使用${}
原因:当我使用#{}的时候,它会自动的帮我加上引号,但降序和升序是不需要引号的
前面说过,#{}会自动的添加上引号,通过下面的例子,来看看为什么排序不建议用#{}
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserInfoMapper { //sort表示是按升序还是降序排,一会我们给sort参数传入desc或者asc @Select("select * from userinfo order by id #{sort}") List
selectUserBySort(String sort); }
②UserInfoMapperTest代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void selectUserBySort() { log.info(userInfoMapper.selectUserBySort("asc").toString()); } }
③运行结果
注意:asc和desc在SQL语句中是不需要添加引号的
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserInfoMapper { //sort表示是按升序还是降序排,一会我们给sort参数传入desc或者asc @Select("select * from userinfo order by id ${sort}") List
selectUserBySort(String sort); }
②UserInfoMapperTest代码package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void selectUserBySort() { log.info(userInfoMapper.selectUserBySort("asc").toString()); } }
③运行结果
当使用到SQL语句模糊查询的时候,使用${}
原因:当我使用#{}的时候,它会自动的帮我加上引号
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.catalina.User; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserInfoMapper { @Select("select * from userinfo where username like '%#{username}%'") List
selectUserByLike(String username); }
②UserInfoMapperTest代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void selectUserByLike() { log.info(userInfoMapper.selectUserByLike("java").toString()); } }
③运行结果
①UserInfoMapper代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import org.apache.catalina.User; import org.apache.ibatis.annotations.*; import java.util.List; @Mapper public interface UserInfoMapper { @Select("select * from userinfo where username like '%${username}%'") List
selectUserByLike(String username); }
②UserInfoMapperTest代码
package com.hlizoo.demo.mapper; import com.hlizoo.demo.model.UserInfo; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @Slf4j //切记一定要加@SpringBootTest @SpringBootTest class UserInfoMapperTest { @Autowired UserInfoMapper userInfoMapper; @Test void selectUserByLike() { log.info(userInfoMapper.selectUserByLike("java").toString()); } }
③运行结果
概念:数据库连接池负责分配、管理和释放数据库连接
特点:它允许应用程序重复使用⼀个现有的数据库连接, 而不是再重新创立一个
优点:
①减少了网络开销
②资源重用
③提升了系统的性能
①无连接池:每次执行SQL语句,要先创建⼀个新的连接对象,然后执行SQL语句,SQL语句执行完,再关闭连接对象释放资源;这种重复的创建连接,销毁连接比较消耗资源
②有连接池:程序启动时,会在数据库连接池中创建⼀定数量的Connection对象,当客户请求数据库连接池,会从数据库连接池中获取Connection对象,然后执行SQL,SQL语句执行完,再把Connection归还给连接池
①C3P0
②DBCP
③Druid
④Hikari
目前比较流行的是Hikari和Druid
Hikari : SpringBoot默认使用的数据库连接池
如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要引入相关依赖即可
dependency>
com.alibaba druid-spring-boot-starter 1.1.17