ORM object relation mapping(对象关系映射)
实现思想:将关系型数据库中的表记录映射成对象,通过对象进行展示
public class User{
private Integer id;
private String name;
private String pwd;
}
数据库中表的数据
id name pwd
1 张三 123456
2 李四 123123
映射关系
类 表
对象 表的(行)记录
属性 表的(列)记录
一.为什么使用Mybatis
1.传统JDBC访问数据库
- 使用jdbc时大量代码冗余
- sql写死在程序当中,当sql修改时 类重新编译
- sql执行后的结果resultSet对象,需要手动处理
2.mybatis
- 对jdbc进行封装和简化
- sql和类分离 sql写在映射文件Mapper.xml中,当sql修改时 ,类不需要重新编译
- sql执行后的结果不需要手动处理,mybatis自动转换成Java对象(自动映射)
3.搭建mybatis工程
(1)创建maven工程,并导入jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.chen</groupId>
<artifactId>mavenTestchen</artifactId>
<version>1.0-SNAPSHOT</version>
添加依赖的方式:
通过快捷键ale+insert 进行搜索
www.mvnrepository.com
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
</dependency>
使用小辣椒快速编写实体类
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>
</project>
(2)在resources下进行mybatis-config的文件配置
可以通过properties进行配置 创建jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver //数据库版本为8 com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/system?characterEncoding=UTF-8 jdbc.username=用户名 jdbc.password=密码
<?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文件,之后可以通过${key}访问对应的value值-->
<properties resource="jdbc.properties"></properties>
<!--设置别名-->
<typeAliases>
<!-- 默认生成的别名不区分大小写 user User-->
<!-- <typeAlias type="com.chen.pojo.User"></typeAlias>-->
<!-- 通过包名的方式解决以后实体类非常多且使用多个typeAlias标签-->
<!-- 这个包下的所有实体类都会生成别名-->
<package name="com.chen.pojo"/>
<environments default="develop">
可以有多个environment 当需要用到其他的时候进行更换(通过id)
<environment id="develop">
进行事务管理的方式:可以通过JDBC代理 MANAGER 自己管理事务
<transactionManager type="JDBC"></transactionManager>
配置数据源: 连接池 JNDI:过时了 POOLED 使用连接池 UNPOOLED 不适用连接池
<dataSource type="POOLED">
这里其中的 name 和 value 不要写错
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/数据库名?characterEncoding=UTF-8"></property>
<property name="username" value="数据库用户"></property>
<property name="password" value="数据库密码"></property>
</dataSource>
</environment>
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
mapper文件导入当有多个的时候 可以通过多个mapper标签导入 ./表示当前目录 可以省略
<mappers>
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
(3)进行mapper文件的配置
<?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 为对应接口中的全限定类名
<mapper namespace="com.chen.dao.UserDao">
resultType指定的结果返回到什么对象的类型中
mybatis-config中配置 这里可以直接用User作为返回
<select id="findAll" resultType="User">
select * from user
</select>
</mapper>
(4)pojo类 这里采用小辣椒Lombok简化代码
package com.chen.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer user_id;
private String user_name;
private String user_pwd;
}
(5)测试类
@Test
public void findAll() throws IOException {
//1.读取配置文件
InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
//获取工厂会话对象
SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(is);
//通过工厂对象获取sqlsession对象
SqlSession sqlSession = ssf.openSession();
//sqlsession通过namespace+id找到要执行的sql语句
//这里采用动态代理
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<User> all = mapper.findAll();
//遍历数据
for (User u:all){
System.out.println(u);
}
}
进行代码封装 通过static进行加载
package com.chen.test;
import com.chen.dao.UserDao;
import com.chen.pojo.User;
import com.sun.xml.internal.ws.runtime.config.TubelineFeatureReader;
import jdk.internal.dynalink.support.TypeUtilities;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.Null;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import javax.sound.midi.Soundbank;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLOutput;
import java.util.List;
import java.util.Map;
public class UserTest {
public static SqlSessionFactory ssf=null;
static {
try {
InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
ssf=new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void findAll() throws IOException {
// //1.读取配置文件
// InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
// //获取工厂会话对象
// SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(is);
//通过工厂对象获取sqlsession对象
SqlSession sqlSession = ssf.openSession();
//sqlsession通过namespace+id找到要执行的sql语句
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<User> all = mapper.findAll();
//遍历数据
for (User u:all){
System.out.println(u);
}
}
}
4. mybatis执行流程
1.先读取配置文件 mybatis-config.xml EmpMapper.xml 这里进行两个读取
2.通过配置文件创建sqlSessionFactory工厂
3.通过工厂创建sqlSession对象(连接数据库)
4.通过对象执行sql语句 namespace+id 进行sql定位
(1)找到mapper文件和找到要执行的sql语句
(2)执行sql语句 指定返回的结果用什么类型封装
(3)将数据记录到封装的对象(这里通过pojo中的set方法进行)
(4)最后返回List<V>泛型 二.mybatis增删查改
1.UserDao
//查询所有
List<User> findAll();
//添加用户
int addUser(User user);
//删除用户 根据id
int deleteUser(Integer user_id);
//修改用户信息
int updateUser(User user);
//根据id查询用户信息
User findById(Integer user_id);
2.mapper配置文件中
<select id="findAll" resultType="User">
select * from user
</select>
<insert id="addUser">
insert into user values (null,#{user_name},#{user_pwd})
</insert>
<delete id="deleteUser">
delete from user where user_id=#{user_id}
</delete>
<!-- int updateUser(User user);-->
<update id="updateUser">
update user set user_name=#{user_name},user_pwd=#{user_pwd} where user_id=#{user_id}
</update>
<!-- User findById(Integer user_id);-->
<select id="findById" resultType="User">
select * from user where user_id=#{user_id}
</select>
3.测试
public class UserTest {
public static SqlSessionFactory ssf=null;
static {
try {
InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
ssf=new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void findAll() throws IOException {
// //1.读取配置文件
// InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
// //获取工厂会话对象
// SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(is);
//通过工厂对象获取sqlsession对象
SqlSession sqlSession = ssf.openSession();
//sqlsession通过namespace+id找到要执行的sql语句
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<User> all = mapper.findAll();
//遍历数据
for (User u:all){
System.out.println(u);
}
}
@Test
public void addUser() throws IOException {
User user = new User();
user.setUser_name("张三");
user.setUser_pwd("1123");
// InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
// SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
int i = mapper.addUser(user);
if(i>0){
System.out.println("添加成功");
}
}
@Test
public void deleteUser() throws IOException {
// InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
// SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
int i = mapper.deleteUser(21);
if(i>0){
System.out.println("删除成功");
}
}
@Test
public void updateUser(){
User user = new User();
user.setUser_id(4);
user.setUser_name("MC果");
user.setUser_pwd("112233");
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
int i = mapper.updateUser(user);
if(i>0){
System.out.println("修改成功");
}
}
@Test
public void findById(){
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
User byId = mapper.findById(4);
System.out.println(byId);
}
}
三.MyBatis获取
#{}获取 #{}的本质就是占位符赋值 (自动加单引号)
${}获取${}的本质就是字符串拼接(需要手动添加单引号)
若mapper接口方法的参数为多个字面量类型
此时mybatis会把参数放到map集合中,以两种方式存储
arg1,arg2...为键,以参数为值。
param1,param2...为键,以参数为值。
因此只需要通过#{}和${}访问map集合的键,就可以获取相对应的值,一定要注意${}的单引号问题。
若mapper接口方法的参数为map集合类型的参数
只需通过#{}和${}访问map集合的键,就可以获得相对应的值,一定要注意${}的单引号问题。
若mapper接口方法的参数为实体类类型的参数
只需要通过#{}和${}访问实体类中的属性名,就可以获得相对应的属性值,一定要注意${}的单引号问题。
可以在mapper接口方法的参数上设置@param注解
此时mybatis会把这些参数放到map中,以两种方式进行存储。
以@param注解的value属性值为键,以参数为值。
以param1,param2...为键,以参数为值。
只需要通过#{}和${}访问map集合的键,就可以获取相应的值,一定要注意${}的单引号问题
1.@param注解
//通过注解@param设置 此时MyBatis会将参数放在map中以两种方式进行存储
//1.以@param注解属性的value值为键,以参数为值
//2.以param1 param2注解的属性值为键 以参数为值
//根据姓名和密码进行查询
User findNameAndPwd(@Param("user_name") String user_name,
@Param("user_pwd") String user_pwd);
<!-- findNameAndPwd-->
<select id="findNameAndPwd" resultType="User">
select * from user where user_name=#{user_name} and user_pwd=#{user_pwd}
</select>
@Test
public void findNameAndPwd(){
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
User admin = mapper.findNameAndPwd("admin","123456");
System.out.println(admin);
}
2.查询数据转换成map集合
/*
*查询出的数据有多条时,并且将数据转换成map集合
* 1.mapper接口方法的返回值设置为泛型为map的list集合
* List<Map<String,Object>> findAllTomap();
* 2.将每条数据转换成map集合的数据放在一个大的map集合中
* 但是必须要用@MapKey注解 将查询的某个的字段设置为大的map的键
*/
List<Map<String,Object>> findAlltoMap();
@MapKey("user_id")
Map<String,Object> findToMapByKey();
<!-- List<Map<String,Object>> findAlltoMap();-->
<select id="findAlltoMap" resultType="map">
select * from user
</select>
<!-- Map<String,Object> findToMapByKey();-->
<select id="findToMapByKey" resultType="map">
select * from user
</select>
@Test
public void findAlltoMap(){
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<Map<String, Object>> alltoMap = mapper.findAlltoMap();
System.out.println(alltoMap);
}
@Test
public void findToMapByKey(){
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
Map<String, Object> toMapByKey = mapper.findToMapByKey();
System.out.println(toMapByKey);
}
3.模糊查询
//模糊查询
List<User> findLike(@Param("user_name") String user_name);
<!-- List<User> findLike(@Param("user_name") String user_name);-->
<select id="findLike" resultType="User">
select * from user where user_name like "%"#{user_name}"%"
</select>
@Test
public void findLike(){
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<User> all = mapper.findLike("a");
for(User u:all){
System.out.println(u);
}
}
4.获取id自增的主键
<!-- int addUserGetId(User user);
useGeneratedKeys:表示当前添加功能使用自增的主键
keyProperty:将添加的数据的自增主键作为实体类类型的参数的属性赋值
因为增删改返回的都是受影响的行数-->
//添加功能获取id自增主键
int addUserGetId(User user);
<!-- void addUserGetId(User user);-->
<insert id="addUserGetId" useGeneratedKeys="true" keyProperty="user_id">
insert into user values (null,#{user_name},#{user_pwd})
</insert>
@Test
public void addUserGetId(){
User user = new User();
user.setUser_name("qwe");
user.setUser_pwd("123321");
SqlSession sqlSession = ssf.openSession(true);
UserDao mapper = sqlSession.getMapper(UserDao.class);
int i = mapper.addUserGetId(user);
System.out.println(i);
}
四.占位符
1 #{}
(1)#{}:相当于JDBC中{?}问号占位符 ,为了给sql中的参数进行占位,相当于JDBC中的 preparedstatement。并且能防止sql注入攻击。
(2)在#{}为日期类和字符串类进行占位时,在参数传过来时会进行转义处理(自动在日期类和字符串类两边加上单引号)
在mapper中 select * from emp where name=#{name}
在程序执行时 select * from emp where name=?
参数: 张三传入替换占位符
select * from emp where name=张三 --错误
select * from emp where name=’张三’ --正确
2. ${}
${}: 是为SQL片段进行占位,将传过来的sql片段直接拼接在${}占位符所在的位置,相当于JDBC中statement,并且不可以防止SQL注入攻击