目录
是一种优秀的持久层框架,用于简化JDBC的开发
快速入门
利用mybatis查询表中的所有信息
1.创建Spring工程,引入mybatis依赖(在sql中选择Mybatis Famework和Mysql driver)
2.根据表格创建实体类
public class User {
private Integer id;
private String name;
private Short age;
private Short gender;
private String phone;
public User(Integer id, String name, Short age, Short gender, String phone) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.phone = phone;
}
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Short getAge() {
return age;
}
public void setAge(Short age) {
this.age = age;
}
public Short getGender() {
return gender;
}
public void setGender(Short gender) {
this.gender = gender;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", phone='" + phone + '\'' +
'}';
}
}
3.在application.properties中配置数据库四要素
#配置数据库的连接信息
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456
4.定义UserMapper,编写SQL语句
//运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器处理
@Mapper
public interface UserMapper {
//查询全部用户信息
@Select("select * from user")
public List<User> list();
}
5.在test中编写测试代码
@SpringBootTest
//Springboot整合单元测试的注解
class Mybatis1ApplicationTests {
//由于接口不能直接创建对象,但是他会创建代理对象
@Autowired
private UserMapper userMapper;
@Test
public void testListUser(){
List<User> userList=userMapper.list();
userList.stream().forEach(user->{
System.out.println(user);
});
}
}
配置SQL提示
配置之后写错会有提示,会方便很多
在写user的时候没有提示或者直接爆红的话,就要配置idea中Mysql数据库的连接
JDBC
在idea里面对数据库内容进行更改
是sun公司定义的一套操作所有关系型数据库的规则,即接口
各个数据库提供jar包
真正执行的代码是驱动jar包中的实现类
优点:可以通过这个对所有数据库进行操作
可以随时替换底层数据库,访问的java代码不改变
代码实例
public class qwwe {
public static void main(String[] args) throws Exception {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//上面这个写不写都行,因为驱动包里面就已经带着有了
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/db1";
String username = "root";
String password = "1040272215Aa";
Connection connection = DriverManager.getConnection(url,username,password);
//3.定义sql
String sql = "update new1 set salary = 10000 where id = 2 ";
//4.获取sql的对象Statement
Statement statement = connection.createStatement();
//5.执行sql
int count = statement.executeUpdate(sql);
//6.处理结果
System.out.println(count);
//7.释放资源
statement.close();
connection.close();
}
}
数据库连接池
数据库连接池是一个容器,负责分配管理数据库连接
它允许应用程序重复使用一个现有的数据库连接,而不是重新再建一个
释放空闲时间超过最大空闲时间的连接,将会直接释放,来避免因为没有释放连接而引起的数据库连接遗漏
好处:
资源重新用
提升系统影响速度
避免数据库连接遗漏,就是怕有的用户没有连接可用
Spring中默认的连接池是Hikari,怎么将连接池切换成Durid呢?
lombok
lambok会在编译的时候,自动生成对应的java代码,我们使用lambok时,还需安装一个lambok插件(idea自带)
基础操作
删除
@Mapper
public interface EmpMapper {
//根据ID删除数据
@Delete("delete from emp where id= #{id}")
public void delete(Integer id);
}
@SpringBootTest
class SpringBaseApplicationTests {
@Autowired
private EmpMapper empMapper;
@Test
public void testDelete(){
empMapper.delete(16);
}
@Test
void contextLoads() {
}
}
删除一般不需要返回值,如果要返回值的话,可以将代码做如下修改
@Test
public void testDelete(){
int dele=empMapper.delete(16);
System.out.println(dele);
}
//根据ID删除数据
@Delete("delete from emp where id= #{id}")
public int delete(Integer id);
这里返回的值是运行以后影响的行数
如果mapper接口方法形参只有一个普通类型的参数,#{}里面的属性名可以随便写,比如#{id} , #{value}
日志输出
如果要看到后台是怎么运行的,那么需要在properties处配置:
#配置mybatis的日志,指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
再次运行,可以在控制台上看到:
第二行和第三行叫做预编译SQL,他的好处是性能更高,更安全(防止SQL注入)
SQL注入
是通过操作输入的数据来修改事先预定好的SQL语句,以达到执行代码对服务器进行攻击的方法
比如这条语句,1=1恒定为true,所以就算密码错误,也能登陆进去
新增
@Insert("insert into emp (username, name, gender, image, job, entrydate,dept_id,create_time,update_time)"
+"values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptld},#{createTime},#{updateTime})")
public void insert (Emp emp);
@Test
public void testInsert(){
Emp emp=new Emp();
emp.setUsername("Tom");
emp.setName("汤姆");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptld(1);
empMapper.insert(emp);
}
由于要输入的数据很多,所以我们这里可以定义一个实体类,直接传递实体类。
values传入的要和定义的实体类的getter和setter方法名字一样,不然会报错。传入的是属性名,而不是字段名
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
private Integer id;
private String username;
private String password;
private String name;
private Short gender;
private String image;
private Short job;
private LocalDate entrydate;
private Integer deptld;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
我出现了这样的情况是我定义的是deptld,但是在传给value的时候名字不一致,就报错了
主键返回
在数据添加成功后,需要获取插入数据库数据的主键,比如添加套餐数据时,还需要维护套餐菜品关系表数据
默认执行基础操作不会返回主键值
表示返回的主键值是19
修改
//更新员工
@Update("update emp set username=#{username},name=#{name},gender=#{gender},image =#{image},"
+"job=#{job},entrydate=#{entrydate},dept_id=#{deptld},update_time=#{updateTime} where id =#{id}")
public void update(Emp emp);
//更新
@Test
public void testUpdate(){
Emp emp=new Emp();
emp.setId(18);
emp.setUsername("Tom2");
emp.setName("汤姆2");
emp.setImage("1.jpg");
emp.setGender((short)1);
emp.setJob((short)1);
emp.setEntrydate(LocalDate.of(2000,1,1));
emp.setUpdateTime(LocalDateTime.now());
emp.setDeptld(1);
empMapper.update(emp);
}
查询
根据Id查询
//根据ID查询员工
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
//根据ID查询员工
@Test
public void testGetById(){
Emp emp=empMapper.getById(18);
System.out.println(emp);
}
可以看到后面三个字段值全部为null,没有封装进来!
数据封装
实体类属性名和数据库查询返回的字段名一致,mybatis会自动封装
如果实体类属性名和数据库查询返回的字段名不一致,不能自动封装
解决方案:
方案一:给字段起别名 ,让别名与实体类的属性一致
//方案一:给字段起别名 ,让别名与实体类的属性一致
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptld, create_time createTime, update_time updateTime from emp where id = #{id}")
public Emp getById(Integer id);
方案二:通过@Results和@Result注解手动映射封装
//方案二:通过@Results和@Result注解手动映射封装
@Results({
@Result(column = "dept_id",property ="deptld"), //前者表示表中的字段名,后者表示类中的属性名
@Result(column = "create_time",property ="createTime"),
@Result(column = "update_time",property ="updateTime")
})
@Select("select * from emp where id = #{id}")
public Emp getById(Integer id);
方案三:开启mybatis的驼峰命名自动映射的开关
在properties中配置
mybatis.configuration.map-underscore-to-camel-case=true
结果如图,可以都封装进来了
条件查询
//条件查询员工
@Select("select * from emp where name like '%${name}%' and gender=#{gender} and entrydate between #{begin} and #{end} order by update_time desc ")
public List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);
//条件查询
@Test
public void testList(){
List<Emp> emplist=empMapper.list("张",(short)1,LocalDate.of(2010,1,1),LocalDate.of(2020,1,1));
System.out.println(emplist);
}
在模糊查询中引号里面是一个字符串,但是#{}不能直接在字符串中直接使用,所以用$符号,直接拼接,不会生成预编译语句,此时出现的问题是性能低 ,不完全,存在SQL注入问题
concat字符串拼接函数
可以用这个解决问题
@Select("select * from emp where name like concat('%',#{name},'%') and gender=#{gender} and entrydate between #{begin} and #{end} order by update_time desc ")
public List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);
}
XML映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.springbase.mapper.EmpMapper"> <!--这的名字与EmpMapper的全类名保持一致,点击接口名字,右键->copy reference-->
<select id="list" resultType="org.example.springbase.Pojo.Emp"> <!-->id属性与mapper接口方法名一致,后面指的是单条记录所封装的全类名 emp->右键->copy reference-->
select * from emp where name like concat('%',#{name},'%') and gender=#{gender} and entrydate between #{begin} and #{end} order by update_time desc
</select>
</mapper>
public List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);
使用mybatis注解,主要是来完成一些简单的增删改查操作,如果需要实现复杂的SQL功能,建议配置XML来配置映射 语句
动态SQL
随着用户的输入或者外部条件的变化而变化的SQL语句,我们称为动态SQL
<if>
用于判断条件是否成立,使用test属性进行条件判断,如果条件为true,则凭借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">
<mapper namespace="org.example.springbase.mapper.EmpMapper"> <!--这的名字与EmpMapper的全类名保持一致,点击接口名字,右键->copy reference-->
<select id="list"
resultType="org.example.springbase.Pojo.Emp"> <!-->id属性与mapper接口方法名一致,后面指的是单条记录所封装的全类名 emp->右键->copy reference-->
select * from emp <where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
<if test="begin !=null and end !=null">
and entrydate between #{begin}and #{end}
</if>
</where>
order by update_time desc
</select>
</mapper>
@Test
public void testList(){
List<Emp> emplist=empMapper.list("张",null,null,null);
System.out.println(emplist);
<where>
<where>标签的两个作用:只会在子元素有内容的情况下才插入where子句(如果都不成立,就不会生成where),而且会自动去除子句的开头的and或者or
<set>
用于update方法中,动态地在行首插入set关键字,并且会删除额外的逗号
<foreach>
<!--批量删除 delete from emp where id in (18,19,20)-->
<!--collection:遍历的集合
item:遍历出来的元素
separator:分隔符
open:遍历开始前拼接的SQL片段
close:遍历开始后拼接的SQL片段
-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
//批量删除员工
public void deleteByIds(List<Integer> ids);
<sql><include>
如果要查询的字段重复使用,之前的代码存在的问题是复用性差,用这两个标签解决
<sql id="commonSelect"> #名字自己取
select id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_time
from emp
</sql>
<select id="list"
resultType="org.example.springbase.Pojo.Emp"> <!-->id属性与mapper接口方法名一致,后面指的是单条记录所封装的全类名 emp->右键->copy reference-->
<include refid="commonSelect"/>
<where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
<if test="begin !=null and end !=null">
and entrydate between #{begin}and #{end}
</if>
</where>
order by update_time desc
</select>
@Test
public void testList(){
List<Emp> emplist=empMapper.list("张",null,null,null);
System.out.println(emplist);
}
标签:name,gender,id,emp,Mybatis,public,String
From: https://blog.csdn.net/2301_80113113/article/details/140414722