1.初步认识
1.1 什么是框架?
框架是一个半成品,是已经对基础的代码进行了封装并提供相应的API,开发者在使用框架可直接调用封装好的api,能够省去很多代码的编写,从而提高工作效率和开发速度。
1.2 什么是ORM?
ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。
1.3 什么是mybatis框架?
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀==ORM框架==。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索封装。MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录. 半自动化框架。必须写sql语句。即mybatis就是封装与数据库交互的半成品。
2. 如何使用mybatis.
准备条件,先创建一个数据库备用
create database mybatis;
use mybatis;
CREATE TABLE users(id INT PRIMARY KEY AUTO_INCREMENT, NAME
VARCHAR(20), age INT);
INSERT INTO users(NAME, age) VALUES('Tom', 12);
INSERT INTO users(NAME, age) VALUES('Jack', 11);
(1)创建一个maven的java工程。
(2)引入mybatis 和 mysql等驱动需要用到的jar包。
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
</dependencies>
点击maven标志运行jar包
(3)创建一个实体类对象,与开头创建的数据库表对应
@Data
@NoArgsConstructor//无参构造
@AllArgsConstructor//有参构造
public class User {
private int id;
private String name;
private int age;
}
(4)配置mybatis的配置文件---mybatis会读取该文件的内容完成连接数据库的功能。
新建一个mybatisXML
进入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>
<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://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
</configuration>
(5)编写相应的映射文件。
新建一个文件夹,创建一个XML
进入UserMapper编写相应的映射文件 -----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:命名空间:它的值现在可以随便写。
以后必须和dao接口对应。
-->
<mapper namespace="a">
<!--sql语句-->
<!--1.根据id查询用户信息
select:表示查询标签
id:唯一标签.
resultType: 返回结果的类型。 mybatis框架帮你把结果封装到User类型中。
#{}:====>占位符。并且或解析uid的值。
-->
<select id="selectById" resultType="com.lly.entity.User">
select * from users where id=#{uid}
</select>
</mapper>
(6) 把映射文件引入到mybatis配置文件中。
(7) 进行测试
3.CUAD操作
public class UserTest {
@Test
public void selectById() throws Exception{
//1.读取mybatis的配置文件。 连接数据库---
Reader reader = Resources.getResourceAsReader("mybatis");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
//2.获取Session对象---->Connection对象
SqlSession session=sqlSessionFactory.openSession();
//3.执行相应的功能
User user = session.selectOne("a.selectById", 2);
System.out.println(user);
}
//将读取mybatis的配置文件,连接数据库,获取session等操作提取出来,每次运行优先执行一次
SqlSession session;
@Before
public void before() throws Exception{
Reader mybatis = Resources.getResourceAsReader("mybatis");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(mybatis);
session=build.openSession();
}
@Test
public void selectAll(){
List<User> list = session.selectList("a.selectAll");
System.out.println(list);
}
@Test
public void insert(){
User user = new User();
user.setName("汤姆");
user.setAge(8);
session.insert("a.inset", user);
session.commit();
}
@Test
public void delete(){
session.delete("a.delete",9);
session.commit();
}
@Test
public void update(){
User user = new User();
user.setName("唐老鸭");
user.setAge(17);
user.setId(10);
session.update("a.updateUser",user);
session.commit();
}
}
4.实际开发中使用DAO操作
可以自己定义方法
4.1定义一个相关的接口。
(1)定义接口,自定义方法
public List<User> selectAll();
public User selectById(int id);
public int insertUser(User user);
public int updateUser(User user);
public int deleteById(int id);
(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">
<!--namespace:命名空间:它的值现在可以随便写。
以后必须和dao接口对应。
-->
<mapper namespace="com.lly.dao.UserDao">//与接口对应
<!--添加-->
<insert id="insertUser">//id与接口中自定义方法名对应
insert into users(name,age) values(#{name},#{age})
</insert>
<!--修改-->
<update id="updateUser">
update users set name=#{name},age=#{age} where id=#{id}
</update>
<!--删除-->
<delete id="deleteById">
delete from users where id=#{id}
</delete>
<!--这里的id必须和Dao中的方法名一致。-->
<select id="selectById" resultType="com.lly.entity.User">
select * from users where id=#{id}
</select>
<select id="selectAll" resultType="com.lly.entity.User">
select * from users
</select>
</mapper>
(3)测试
public class UserTest {
SqlSession session;
@Before
public void before() throws Exception{
Reader mybatis = Resources.getResourceAsReader("mybatis");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(mybatis);
session=build.openSession();
}
@Test
public void testInsert(){
//得到dao的实现类。由mybatis框架按照映射文件帮你生成
UserDao userDao=session.getMapper(UserDao.class);
User user=new User();
user.setAge(18);
user.setName("葫芦娃");
userDao.insertUser(user); //调用就是dao中自己的方法。
session.commit();
}
}
5.传递多个参数
两种方式
1.
2.
测试
6.特殊字符
示例 两种方法
1.
2.使用<![CDATA[ 特殊字符或SQL语句 ]]>
7.mybatis的优化
7.1 引入db属性文件。
(1)新建一个数据库属性文件. properties
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
jdbc.driverName=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=root
(2)在mybatis配置文件中引入属性文件并使用相应的key
7.2 引入日志文件。----更好的显示sql语句
(1)引入日志jar包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
(2)引入日志的配置文件,新建一个 log4j.properties
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =D://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
测试
7.3 解决列名和属性名不一致。
第一种: 为查询的列起别名;让别名和属性名一致。
<select id="selectById" resultType="com.lly.entity.Order">
select order_id id,order_no no,order_price price from orders where order_id=#{id}
</select>
第二种: 使用resultMap标签 来完成属性和列的映射关系。
<!--
id:唯一标识
type: 类型 ; 表与哪个实体类的映射
<id 主键的映射关系 column="列名" property="属性名"/>
<result 普通字段/>
autoMapping=true 表示自动映射。默认true
-->
<resultMap id="My01" type="com.lly.entity.Order" >
<!--id必写-->
<id property="id" column="order_id"/>
<result property="no" column="order_no"/>
<result property="price" column="order_price"/>
</resultMap>
<!--注意:使用了resultMap不能在使用resultType-->
<select id="selectById" resultMap="My01" >
select * from orders where order_id=#{id}
</select>
8.链表查询
8.1 多对一
新建表备用
(1) 根据订单id查询订单信息以及该订单对应的用户信息。
第一种方式 通过链表查询。
<resultMap id="My01" type="com.lly.entity.Order" >
<!--id必写-->
<id property="id" column="order_id"/>
<result property="price" column="order_price"/>
<result property="num" column="num"/>
<!--association:表示多对一
property:表示对象属性名
javaType:表示该对象所属的类型
autoMapping必须写
-->
<association property="user" javaType="com.lly.entity.User" autoMapping="true">
<!--User和User表的对应关系-->
<id property="id" column="id"/>
</association>
</resultMap>
<!--注意:使用了resultMap不能在使用resultType-->
<select id="selectById" resultMap="My01" >
select * from orders o join users u on o.uid=u.id where o.order_id=#{id}
</select>
第二种方式 通过嵌套查询。----两次查询。
8.2一对多
从一的一方查询多的一方。
比如: 班级--1---n-->学生.
创建表备用
CREATE TABLE class(
c_id INT PRIMARY KEY AUTO_INCREMENT,
c_name VARCHAR(20),
);
INSERT INTO class(c_name) VALUES('A');
INSERT INTO class(c_name) VALUES('B');
INSERT INTO class(c_name) VALUES('C');
CREATE TABLE student(
s_id INT PRIMARY KEY AUTO_INCREMENT,
s_name VARCHAR(20),
class_id INT
);
INSERT INTO student(s_name, class_id) VALUES('xs_A', 1);
INSERT INTO student(s_name, class_id) VALUES('xs_B', 1);
INSERT INTO student(s_name, class_id) VALUES('xs_C', 2);
INSERT INTO student(s_name, class_id) VALUES('xs_D', 2);
INSERT INTO student(s_name, class_id) VALUES('xs_E', 3);
INSERT INTO student(s_name, class_id) VALUES('xs_F', 3);
例子:根据班级id查询班级信息以及该班级下所有的学生信息。
<resultMap id="My03" type="com.lly.entity.Clazz">
<id column="c_id" property="cid"/>
<result property="cname" column="c_name"/>
<!--
collection: 集合的意思 多的意思
property:集合对象名
ofType: 集合的泛型
-->
<collection property="students" ofType="com.lly.entity.Student" autoMapping="true">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
<result property="classId" column="class_id"/>
</collection>
</resultMap>
<!--这里的id必须和Dao中的方法名一致。-->
<select id="findById" resultMap="My03">
select * from class c join student s on c.c_id=s.class_id where c_id=#{id}
</select>
9.动态SQL语句
(1)if和where一起用
<!--如果传入了书名 则按照书名进行查询 如果没有传入书名 则查询所有
where:可以帮你添加where关键 并且把第一个and | or去除
-->
<select id="findByCondition" resultMap="map">
select * from book_info
<where>
<if test="bookname!=null and bookname!=''">
and book_name=#{bookname}
</if>
<if test="author!=null and author!=''">
and book_author=#{author}
</if>
</where>
</select>
测试:
@Test
public void testSelect01(){
BookDao bookDao = session.getMapper(BookDao.class);
Map<String,Object> map=new HashMap<String,Object>();//从网页中得到参数值 并且封装到map对象中。
map.put("bookname1","西游记");
map.put("author","罗贯中");
List<Book> list = bookDao.findByCondition(map);
}
(2) [choose when otherwise] 和where
<!--choose +where
when:当条件满足时不会执行下面的when和other 都不满足则执行otherwise
-->
<select id="findByCondition2" resultMap="map">
select * from book_info
<where>
<choose>
<when test="bookname!=null and bookname!=''">
and book_name=#{bookname}
</when>
<when test="author!=null and author!=''">
and book_author=#{author}
</when>
<otherwise>
and book_price>35
</otherwise>
</choose>
</where>
</select>
@Test
public void testSelect02(){
BookDao bookDao = session.getMapper(BookDao.class);
Map<String,Object> map=new HashMap<String,Object>();//从网页中得到参数值 并且封装到map对象中。
map.put("bookname","西游记");
map.put("author","施耐庵");
List<Book> list = bookDao.findByCondition2(map);
}
(3)set标签。修改部分字段。
<!--修改部分列的值。
set 可以帮你添加set关键字 并且去除最后的逗号。
-->
<update id="update">
update book_info
<set>
<if test="name!=null and name!=''">
book_name=#{name},
</if>
<if test="author!=null and author!=''">
book_author=#{author},
</if>
<if test="pub!=null and pub!=''">
book_pub=#{pub},
</if>
<if test="price!=null">
book_price=#{price},
</if>
</set>
where book_id=#{id}
</update>
@Test
public void testUpdate(){
BookDao bookDao = session.getMapper(BookDao.class);
Book book=new Book();
book.setAuthor("鲁迅");
book.setName("狂人日记");
book.setId(1002);
bookDao.update(book);
session.commit();
}
(4) foreach 批量删除。
<!--
delete from book_info where id in(1001,1002,1003)
in (1001,1002,1003)
foreach:
collection:要遍历的集合和数组名
item: 每次遍历时赋值的元素变量名
open: 以什么开始
close:以什么结束
separator: 分隔符
-->
<delete id="batchDelete">
delete from book_info where book_id in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
@Test
public void testUpdat2e(){
BookDao bookDao = session.getMapper(BookDao.class);
int [] ids={1001,1002,1003};
bookDao.batchDelete(ids);
session.commit();
}
9.模糊查询
10.分页插件--PageHelper
(1) 引入相关的pageHelper依赖
<!--分页插件的依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.11</version>
</dependency>
(2) 加入拦截
(3)测试
@Test
public void testUpdate3(){
EmpDao empDao = session.getMapper(EmpDao.class);
//使用分页功能 request.getParamter("page") request.getParamter("pageSize")
PageHelper.startPage(2,10);
List<Emp> list = empDao.findAll3("王");
//可以把查询的结果封装到PageInfo类中 包含你想要的任何信息
PageInfo<Emp> pageInfo=new PageInfo<Emp>(list);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("当前页码的数据:"+pageInfo.getList());
}