1. mybatis框架
框架:别人搭建好的某些功能,只需要引用该框架并加入自己的业务代码。
好处: 提高开发效率。
mybatis的介绍:
MyBatis 是一款优秀的持久层Dao框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Java实体类)映射成数据库中的记录.
2. 为什么使用mybatis框架
可以简化jdbc的操作以及占位符赋值以及查询结果集的封装。
3. 如何使用mybatis.
(1)引入mybatis和mysql的jar包
<!--mybatis驱动-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
(2) 创建mybatis的配置文件,命名为:mybatis.xml
<?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.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<!--注册映射文件-->
<mappers>
<mapper resource="mapper/userMapper.xml"/>
</mappers>
</configuration>
(3) 创建实体类(用Lombok插件)
@Data(自动生成get和set方法)
@NoArgsConstructor(无参构造)
@AllArgsConstructor(有参构造)
public class User {
private Integer id;
private String name;
private int email;
public User(String name, int email) {
this.name = name;
this.email = email;
}
}
(4) 创建mybatis和数据库的映射文件.命名为:xxx.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">
<!--namespace:命名空间,可以随便起名,后期要求命名空间的值必须和所对应的dao相同-->
<mapper namespace="com.cmw.entity.Student">
<!--查询 根据id查询用户信息
select标签用于查询的标签
id:标签的唯一标识
resultType:定义返回的类型,把sql查询的结果封装到那个实体类中
parameterType:参数类型
#{id}===》表示占位符 等价? 是mybatis的框架语法
#{必须和属性对应}
-->
<select id="findById" resultType="Student">
select * from student where id=#{id}
</select>
(4) 测试mybatis
package com.cmw.test;
import com.cmw.entity.Student;
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.Reader;
/**
* @Author 86151
* @Create 2022/5/31 - 15:18
*/
public class Test01 {
public static void main(String[] args) throws Exception{
//1.读取mybatis配置文件的内容
Reader reader= Resources.getResourceAsReader("mybatis.xml");
//2.获取SqlSessionFactory对象
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
//3.获取SqlSession对象----封装了对数据库操作的各种方法
SqlSession session= factory.openSession();
//调用查询一个结果的接口 String statement:命名空间+id---指向SQL标签
// Object parameter:需要实参
Student student =session.selectOne("com.cmw.entity.Student.findById","2");
System.out.println(student);
//4.关闭
session.close();
}
}
4. 使用mybatis完成crud(即增删改查)
<?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:命名空间的值必须和所对应的dao相同-->
<mapper namespace="com.cmw.entity.Student">
<!--查询 根据id查询用户信息
select标签用于查询的标签
id:标签的唯一标识
resultType:定义返回的类型,把sql查询的结果封装到那个实体类中
parameterType:参数类型
#{id}===》表示占位符 等价? 是mybatis的框架语法
#{必须和属性对应}
-->
<select id="findById" resultType="Student">
select * from student where id=#{id}
</select>
<!--增加-->
<insert id="add" parameterType="Student">
insert into student values(null ,#{name},#{realname})
</insert>
<!--删除-->
<delete id="delete" parameterType="int">
delete from student where id=#{id}
</delete>
<!--修改-->
<update id="update" parameterType="Student">
update student set name=#{name},realname=#{realname} where id=#{id}
</update>
<!--查询所有-->
<select id="findAll" resultType="Student">
select * from student
</select>
</mapper>
测试:
package com.cmw.test;
import com.cmw.entity.Student;
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;
/**
* @Author 86151
* @Create 2022/5/31 - 16:13
*/
public class Test1 {
//添加
@Test
public void testAdd() throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
Student student=new Student();
student.setName("lm");
student.setRealname("黎明");
int row = session.insert("com.Student.add", student);
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 delete = session.delete("com.Student.delete", 1);
System.out.println(delete);
session.close();
}
//修改
@Test
public void testUpdate() throws Exception{
//1.读取mybatis配置文件的内容
Reader reader = Resources.getResourceAsReader("mybatis.xml");
//2.获取SqlSessionFactory对象
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
//3.获取SqlSession对象---封装了对数据库的各种方法
SqlSession session = factory.openSession();
Student student=new Student(3,"xx","嘻嘻");
int i = session.update("com.Student.update", student);
System.out.println(i);
//提交查询
session.commit();
session.close();
}
//查询所有
@Test
public void testFindAll() throws Exception{
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
SqlSession session = factory.openSession();
List<Object> list = session.selectList("com.Student.findAll");
System.out.println(list);
session.commit();
session.close();
}
}
5. mybatis一些优化
5.1 为实体类起别名
mybatis.xml配置文件
<typeAliases> <!--单独为某个实体类 起个别名 <typeAlias type="com.cmw.entity.Student" alias="student"/>--> <!--为指定包下的实体类 起个别名 该别名就是实体类名--> <package name="com.cmw.entity"/> </typeAliases>
5.2 添加sql日志
(1)添加日志的jar.(在pom.xml里面添加)
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
(2) 添加日志的文件配置且命名为:log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
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.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=D:/qy151/log/qy151.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
6. 通过dao和映射文件的关联来完成操作---企业开发模式
由于SqlSession封装的方法,传递的参数statement, 传递占位符的参数只能传递一个。而且他的方法名称都是固定。而真实在开发环境下我们不使用SqlSession封装的方法,习惯自己定义方法,自己调用自己的方法。
(1)创建一个dao接口并定义自己需要的方法。
package com.cmw.dao;
import com.cmw.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserDao {
//查询所有用户的信息
public List<User> findAll();
}
(2)创建映射文件
<?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="com.cmw.dao.UserDao">
<!--查找所有-->
<select id="findAll" resultType="com.cmw.entity.User">
select * from tb_user
</select>
</mapper>
注意: namespace必须和dao接口一样,标签的id必须和接口的方法名一样。
(3)测试
package com.cmw.test;
import com.cmw.dao.UserDao;
import com.cmw.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;
/**
* @Author 86151
* @Create 2022/6/1 - 10:47
*/
public class TestUserDao {
//查询所有
@Test
public void testFindAll() 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<User> list = userDao.findAll();
System.out.println(list);
session.commit();
session.close();
}
7.传递多个参数。
我们在dao接口中某些方法可能需要传递多个参数,需要在参数处使用@Param()为参数起名。
package com.cmw.dao;
import com.cmw.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserDao {
/**
* 根据id查询用户信息
* @param name
* @param email
* @return
*/
//@param 表示把该参数的名称作为映射文件的参数名
public User findNameAndEmail(@Param("name")String name,@Param("email")int email);
}
8.添加时如何返回递增的主键值。
需要返回添加数据库后的id值。
<!--添加内容
useGeneratedKeys:设置使用生成的主键
keyProperty:赋值给哪个属性
-->
<insert id="add" parameterType="com.cmw.entity.User" useGeneratedKeys="true" keyProperty="id">
insert into tb_user values(null,#{name},#{email})
</insert>
测试及结果
//添加
@Test
public void testAdd() 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("赵六",7415);
System.out.println("添加前的id"+user);
userDao.add(user);//添加user
System.out.println("添加后的id"+user);
session.commit();
session.close();
}
9.解决列名和属性名不一致。
问题: 查询时返回一个null,或者某个列没有值
可以有两种解决办法:
第一种: 为查询的列起别名,而别名和属性名一致。
<!--根据id查询学生信息-->
<select id="findOne" resultType="com.cmw.entity.Student">
select tb_id id,tb_name name,tb_age age,sex from tb_stu where tb_id=#{id}
</select>
第二种: 使用resultMap完成列和属性之间的映射关系。
<!--resultType和resultMap 二者只能用一个-->
<resultMap id="stuMapper" type="com.cmw.entity.Student">
<!--主键的映射关系 column:列名 property:属性名-->
<id column="tb_id" property="id"/>
<!--普通列的映射关系-->
<result column="tb_name" property="name"/>
<result column="tb_age" property="age"/>
</resultMap>
<select id="findOne" resultMap="stuMapper">
select * from tb_stu where tb_id=#{id}
</select>
注意:resultMap的id 和 select的resultMap的值一样
如果列名和属性名有个别一致的,可以在resultMap中不写映射关系
10. 动态sql
10.1 什么是动态sql:
顾名思义,SQL 是动态拼接成的,根据传入的变量值进行逻辑操作,并动态拼接,方便实现多条件下的数据库操作。 在业务逻辑复杂,即简单 SQL 无法完成时,需要拼接时就要使用动态 SQL。
10.2 mybatis中动态sql标签有哪些?
if:
适用于动态的包含where字句的一部分
if的特点是
当if的判断条件满足时,添加if标签中的字句
当if的判断条件不满足时,什么都不添加
choose:
适用于:
当判断的条件为true时,执行一个语句
当判断的条件为false时,执行另一个语句
where和set:
where的作用:
1、当where标签中的语句不为空时,会在语句之前拼接上“where”关键字
2、假如where标签中的语句是以“and”或者“or”开头,那么这个“and”或者“or”会被省略掉
set的作用:
1、假如set标签中的语句不为空,那么会在开头拼接“set”关键字
2、假如set标签中的语句是以“,”结尾,那么这个“,”会被去掉
Trim:
prefix:前缀,在赶回的字符串之前添加什么内容
suffix:后缀,在返回的字符串之后添加什么内容
prefixoverrides:当字符串以其中的内容开头时,该内容会被覆盖
suffixoverrides:当字符串以其中的内容结尾时,该内容会被覆盖
Foreach:
注意:当接口中方法的参数为数组或者集合时,mybatis会自动的把该参数封装成一个map
map的key为参数类型,首字母小写
默认:数组的key为“array”,集合的key为“list”,map的key为“map”
collection:参数在封装成的map中的key值
open:表示字符串以什么开始
close:表示字符串以什么结束
item:给集合中的每一个元素起的别名
separator:集合中元素的分隔符
10.3 if标签--单条件判断
package com.cmw.dao;
import com.cmw.entity.Account;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface AccountDao {
//如果name不为null,则按照name查询,如果为null则查询所有
public List<Account> findByCondition(@Param("name")String name,@Param("money")Double money);
}
<select id="findByCondition" resultType="com.cmw.entity.Account">
select * from account where 1=1
<if test="name!=null and name!=''">
and name=#{name}
</if>
<if test="money!=null">
and money=#{money}
</if>
</select>
10.4 choose和when标签 多条件分支判断
package com.cmw.dao;
import com.cmw.entity.Account;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface AccountDao {
//choose
public List<Account> findByCondition2(@Param("name")String name,@Param("money")Double money);
}
<select id="findByCondition2" resultType="com.cmw.entity.Account">
select * from account where 1=1
<choose>
<when test="name!=null and name!=''">
and name=#{name}
</when>
<when test="money!=null">
and money=#{money}
</when>
<otherwise>
and isdeleted=0
</otherwise>
</choose>
</select>
10.5 where标签
我们观察到上面的sql都加了 where 1=1 ,如果不使用where 1=1 那么你的动态sql可能会出错。 我们能不能不加where 1=1呢! 可以 那么我们就可以使用where标签,作用:可以自动为你添加where关键字,并且可以帮你去除第一个and |or
<select id="findByCondition" resultType="com.cmw.entity.Account">
select * from account
<where>
<if test="name!=null and name!=''">
and name=#{name}
</if>
<if test="money!=null">
and money=#{money}
</if>
</where>
</select>
10.6 set标签
配合if标签一起用,一般用在修改语句。如果传递的参数值为null,那么应不修改该列的值。
<!--set:生成关键字set 并且可以去除最后一个逗号-->
<update id="update">
update account
<set>
<if test="name!=null and name=''">
name =#{name},
</if>
<if test="money!=null">
money=#{money},
</if>
<if test="isdeleted!=null">
isdeleted=#{isdeleted},
</if>
<if test="created!=null">
created=#{created},
</if>
<if test="updated!=null">
updated=#{updated},
</if>
</set>
where id=#{id}
</update>
10.7 foreach标签
循环标签.
查询:
<sql id="a">
id,name,money,isdeleted,created,updated
</sql>
<select id="findByIds" resultType="com.cmw.entity.Account">
select <include refid="a" /> from account where id in(
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>)
</select>
删除:
<delete id="batchDelete">
delete from account where id in (
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>
)
</delete>
添加:
<insert id="batchAdd">
insert into account(name ,isdeleted) values
<foreach collection="list" item="acc" separator=",">
(#{acc.name},#{acc.isdeleted})
</foreach>
</insert>