源于动力节点mybatis,复习使用
文章目录
三层架构
- 界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。(jsp ,html ,servlet)
- 业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
- 数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等的。
-
三层对应的包
界面层: controller包 (servlet)
业务逻辑层: service 包(XXXService类)
数据访问层: dao包(XXXDao类) -
三层中类的交互
用户使用界面层–> 业务逻辑层—>数据访问层(持久层)–>数据库(mysql) 用户在界面层发起请求,请求传递到业务逻辑层,业务逻辑层经过处理,通过持久层访问数据库拿到数据信息。业务逻辑 层处理加工信息,把执行结果通过界面层展示给用户。
-
三层对应的处理框架
界面层—servlet—springmvc(框架)
业务逻辑层—service类–spring(框架)
数据访问层—dao类–mybatis(框架)
框架的介绍
框架是一个软件,半成品的软件,定义好了一些基础功能, 需要加入你的功能就是完整的。
基础功能是可重复使用的,可升级的。
框架特点:
- 框架一般不是全能的, 不能做所有事情
- 框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的。
- 框架是一个软件
mybatis框架的介绍
使用jdbc开发
public void findStudent() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//注册 mysql 驱动
Class.forName("com.mysql.jdbc.Driver");
//连接数据的基本信息 url ,username,password
String url = "jdbc:mysql://localhost:3306/springdb";
String username = "root";
String password = "123456";
//创建连接对象
conn = DriverManager.getConnection(url, username, password);
//保存查询结果
List<Student> stuList = new ArrayList<>();
//创建 Statement, 用来执行 sql 语句
stmt = conn.createStatement();
//执行查询,创建记录集,
rs = stmt.executeQuery("select * from student");
while (rs.next()) {
Student stu = new Student();
stu.setId(rs.getInt("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
//从数据库取出数据转为 Student 对象,封装到 List 集合
stuList.add(stu);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
//关闭资源
if (rs != null) ;
{
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用jdbc:
- 代码比较多,开发效率低
- 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
- 对 ResultSet 查询的结果,需要自己封装为 List
- 重复的代码比较多些
- 业务代码和数据库的操作混在一起
mybatis框架的功能
一个框架,早期叫做ibatis, 代码在github。mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)
-
sql mapper :sql映射
可以把数据库表中的一行数据 映射为 一个java对象。
一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据 -
Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。
mybatis提供了哪些功能:
- 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了
- 提供了执行sql语句的能力, 不用你执行sql
- 提供了循环sql, 把sql的结果转为java对象, List集合的能力
- 提供了关闭资源的能力,不需要关闭Connection, Statement, ResultSet
而开发人员做的是: 提供sql语句
最后是: 开发人员提供sql语句–mybatis处理sql—开发人员得到List集合或java对象(表中的数据)
总结:
mybatis是一个sql映射框架,提供的数据库的操作能力。增强版的JDBC。
mybatis入门
创建表
CREATE TABLE `student` (
`id` int(11) NOT NULL ,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
输入数据:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uM16VgpR-1641562178727)(mybatis.assets/table_data.png)]
idea创建maven项目
创建一个空工程
在新工程下创建module:
新创建pom文件中build下,可以直接删除:(写不写都是依赖这些插件,默认给出了是方便用户自己配置)
加入maven坐标,依赖,插件
<?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>ysk</groupId>
<artifactId>01-hello-mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
</dependencies>
<!-- 资源插件:编译后会拷贝src/main/java文件夹下的非java文件到target/classes文件夹下-->
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
类、接口、映射文件
-
实体类
package ysk.domain; //类的名称建议和表名一样 public class Student { //属性和列名一样 private Integer id; private String name; private String email; private Integer age; 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 String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", email='" + email + '\'' + ", age=" + age + '}'; } }
-
接口
package ysk.dao; import ysk.domain.Student; import java.util.List; public interface StudentDao { //查询所有学生信息 public List<Student> selectStudents(); }
-
编写 Dao 接口 Mapper 映射文件 StudentDao.xml
- 在 dao 包中创建文件 StudentDao.xml
- 要 StudentDao.xml 文件名称和接口 StudentDao 一样,区分大小写的一样
StudentDao.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="ysk.dao.StudentDao">
<!--namespace:必须有值,自定义的唯一字符串
推荐使用:dao 接口的全限定名称 -->
<select id="selectStudents" resultType="ysk.domain.Student">
<!--
select:表示查询操作。
id: 你要执行的sql语法的唯一标识, mybatis会使用这个id的值来找到要执行的sql语句
可以自定义,但是要求你使用接口中的方法名称。(简单的来说就是给这条sql语句起了个名字)
resultType:表示结果类型的, 是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型。
值写的类型的全限定名称(这条sql语句执行后的返回值)
-->
select id,name,email,age from student order by id
</select>
</mapper>
sql映射文件(sql mapper): 写sql语句的, mybatis会执行这些sql
1.指定约束文件<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
mybatis-3-mapper.dtd是约束文件的名称, 扩展名是dtd的。
2.约束文件作用: 限制,检查在当前文件中出现的标签,属性必须符合mybatis的要求。
3.mapper 是当前文件的根标签,必须的。
namespace:叫做命名空间,唯一值的, 可以是自定义的字符串。
要求你使用dao接口的全限定名称。4.在当前文件中,可以使用特定的标签,表示数据库的特定操作。
<select>:表示执行查询,select语句 <update>:表示更新数据库的操作, 就是在<update>标签中 写的是update sql语句 <insert>:表示插入, 放的是insert语句 <delete>:表示删除, 执行的delete语句
mybatis的主配置文件
项目 src/main 下创建 resources 目录,设置 resources 目录为 resources root 创建主配置文件:名称为 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="mydev">
<!-- environment : 一个数据库信息的配置, 环境
id:一个唯一值,自定义,表示环境的名称。
下面可以写多个environment,default控制用哪个
-->
<environment id="mydev">
<!--
transactionManager :mybatis的事务类型
type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示数据源,连接数据库的
type:表示数据源的类型, POOLED表示使用连接池
-->
<dataSource type="POOLED">
<!--
driver, user, username, password 是固定的,不能自定义。
-->
<!--数据库的驱动类名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接数据库的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--访问数据库的用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<!--一个mapper标签指定一个文件的位置。
从类路径开始的路径信息。 target/clasess(类路径)
-->
<mapper resource="ysk/dao/StudentDao.xml"/>
<!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
</mappers>
</configuration>
测试
main目录下新建测试类:
clasess目录下面的文件才是程序执行时所需要的
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 ysk.domain.Student;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Hello {
public static void main(String[] args) throws IOException {
//访问mybatis读取student数据
//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
//clasess目录下面的文件才是程序执行时所需要的
String config="mybatis.xml";
//2.读取这个config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建了SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
//5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
SqlSession sqlSession = factory.openSession();
//6.【重要】指定要执行的sql语句的标识。 sql映射文件中的namespace + "." + 标签的id值
//String sqlId = "com.bjpowernode.dao.StudentDao" + "." + "selectStudents";
//namespace.id值为sqlId的执行语句
String sqlId = "ysk.dao.StudentDao.selectStudents";
//7. 重要】执行sql语句,通过sqlId找到要执行的sql语句
List<Student> studentList = sqlSession.selectList(sqlId);
//8.输出结果
//studentList.forEach( stu -> System.out.println(stu));
for(Student stu : studentList){
System.out.println("查询的学生="+stu);
}
//9.关闭SqlSession对象
sqlSession.close();
}
}
读取成功:
出现问题几种解决方法
- 检查是否加入了资源插件
- 先 clean再compile
- 上方窗口中build的rebuild project
- 上方窗口中file的Invalidate Caches
- 手工拷贝复制target不存在的文件
配置日志功能
mybatis.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
基本的增删改查
insert
-
StudentDao接口中增加方法
int insertStudent(Student student); //返回插入信息的条数
-
sql映射文件
插入的具体格式是
#{ }
,没有返回的实体类类型,所以不用resultType这个属性<insert id="insertStudent"> insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age}) </insert>
-
测试类
注意! 创建测试类的时候类名不要起名为 Test!
不是自动提交事务,需要手动设置
session.commit();
package ysk; 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 ysk.domain.Student; import java.io.IOException; import java.io.InputStream; public class TestMybatis { @Test public void testInsert() throws IOException { //1.mybatis 主配置文件 String config = "mybatis.xml"; //2.读取配置文件 InputStream in = Resources.getResourceAsStream(config); //3.创建 SqlSessionFactory 对象 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); //4.获取 SqlSession SqlSession session = factory.openSession(); //5.创建保存数据的对象 Student student = new Student(); student.setId(1099); student.setName("张丽"); student.setEmail("[email protected]"); student.setAge(20); //6.执行插入 insert int rows = session.insert( "ysk.dao.StudentDao.insertStudent",student); //7.不是自动提交事务,需要手动设置 session.commit(); System.out.println("增加记录的行数:"+rows); //8.关闭 SqlSession session.close(); } }
mybatis对象分析
对象使用
-
Resources 类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返 回不同类型的 IO 流对象。
-
SqlSessionFactoryBuilder 类
SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由 于 SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将 该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。
-
SqlSessionFactory 接口
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用 只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。、
-
openSession(true):创建一个有自动提交功能的 SqlSession
-
openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
-
openSession():同 openSession(false)
从而,可以这样简化写法:
//获取SqlSession对象,从SqlSessionFactory中获取SqlSession SqlSession sqlSession = factory.openSession(); //mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务 sqlSession.commit(); //直接这样写也可以 SqlSession sqlSession = factory.openSession(true);
-
-
SqlSession 接口
SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以 SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。 SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将 其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。
编写工具类
package ysk.utils;
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.IOException;
import java.io.InputStream;
public class MyBatisUtils {
private static SqlSessionFactory factory = null;
static {
String config = "mybatis.xml";
try {
InputStream in = Resources.getResourceAsStream(config);
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession的方法
public static SqlSession getSqlSession() {
SqlSession sqlSession = null;
if (factory != null) {
sqlSession = factory.openSession();// 非自动提交事务
}
return sqlSession;
}
}
使用工具类
SqlSession session = MyBatisUtils.getSqlSession();
//5.创建保存数据的对象
Student student = new Student();
student.setId(1050);
student.setName("张丽");
student.setEmail("[email protected]");
student.setAge(20);
//6.执行插入 insert
int rows = session.insert(
"ysk.dao.StudentDao.insertStudent",student);
//7.不是自动提交事务,需要手动设置
session.commit();
System.out.println("增加记录的行数:"+rows);
//8.关闭 SqlSession
session.close();
使用idea创建模板
- 创建mapper文件模板
-
创建主配置文件模板
同上
传统 dao改进
StudentDao类几乎没有用到,主要还是用到了sqlsession的方法,StudentDao类主要是做一个指引的指示
-
定义接口以及实现类
package ysk.dao.impl; import org.apache.ibatis.session.SqlSession; import ysk.dao.StudentDao; import ysk.dao.utils.MyBatisUtils; import ysk.domain.Student; import java.util.List; public class StudentDaoImpl implements StudentDao { @Override public List<Student> selectStudents() { SqlSession session = MyBatisUtils.getSqlSession(); String sqlId = "ysk.dao.StudentDao.selectStudents"; List<Student> stu = session.selectList(sqlId); //关闭 session.close(); return stu; } @Override public int insertStudent(Student student) { SqlSession session = MyBatisUtils.getSqlSession(); String sqlId = "ysk.dao.StudentDao.insertStudent"; int nums = session.insert(sqlId,student); session.commit(); //提交事务 session.close(); //关闭 return nums; } }
-
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"> <mapper namespace="ysk.dao.StudentDao"> <select id="selectStudents" resultType="ysk.domain.Student"> select id,name,email,age from student order by id </select> <insert id="insertStudent"> insert into student values(#{id},#{name},#{email},#{age}) </insert> </mapper>
以上代码还是有大量重复冗余的代码,可以继续封装。
MyBatis 框架 Dao 代理
MyBatis 框架 Dao 代理
主要作用:干掉dao的实现类
只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定 Dao 接口类的 class 值。
mybatis根据 dao的方法调用,获取执行sql语句的信息
mybatis根据dao接口,创建dao接口的实现类, 并创建该类的对象,完成SqlSession调用方法, 访问数据库
具体如何创建如何执行:
使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口),getMapper能获取dao接口对应的实现类对象,
mybatis内部通过接口名和方法名映射到对应xml文件中的sql语句执行
注意:这里,接口中定义的方法名称和StudentDao.xml 中的id要保持一样。
具体代码:
package ysk;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import ysk.dao.StudentDao;
import ysk.dao.utils.MyBatisUtils;
import ysk.domain.Student;
import java.util.List;
public class TestMybatis {
@Test
public void testSelect(){
SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
List<Student> stu = dao.selectStudents();
for (Student student : stu) {
System.out.println(student);
}
session.close();
}
@Test
public void testInsert(){
SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
Student student= new Student();
student.setId(1071);
student.setName("盾山");
student.setEmail("[email protected]");
student.setAge(1111);
int nums = dao.insertStudent(student);
session.commit(); //提交事务!!!
session.close();
System.out.println("nums="+nums);
}
}
深入理解参数
parameterType
parameterType: 接口中方法参数的类型, 类型的完全限定名或别名。这个属性是可选的,一般不写。因为 MyBatis 可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从 java 代码传入到 mapper 文件的 sql 语句。
<select id="selectStudentById" parameterType="java.lang.Integer" resultType="ysk.domain.Student">
select id,name, email,age from student where id=${id}
</select>
MyBatis 传递参数
从 java 代码中把参数传递到 mapper.xml 文件。
一个简单参数
Dao 接口中方法的参数只有一个简单类型(java 基本类型和 String),占位符 #{ 任意字符 },和方法的参数名无关。
接口
Student selectStudentById(Integer id);
StudentDao.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="ysk.dao.StudentDao">
<select id="selectStudentById" resultType="ysk.domain.Student">
select id,name,email,age from student where id=#{id}
</select>
<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age})
</insert>
</mapper>
测试
@Test
public void testSelect(){
SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
Student student = dao.selectStudentById(1001);
System.out.println(student);
session.close();
}
使用#{}
之后, mybatis执行sql是使用的jdbc中的PreparedStatement
对象
由mybatis执行下面的代码:
//使用#{}之后, mybatis执行sql是使用的jdbc中的PreparedStatement对象
由mybatis执行下面的代码:
1. mybatis创建Connection , PreparedStatement对象
String sql="select id,name, email,age from student where id=?";
PreparedStatement pst = conn.preparedStatement(sql);
pst.setInt(1,1001);
2. 执行sql封装为resultType="com.bjpowernode.domain.Student"这个对象
ResultSet rs = ps.executeQuery();
Student student = null;
while(rs.next()){
//从数据库取表的一行数据, 存到一个java对象属性中
student = new Student();
student.setId(rs.getInt("id));
student.setName(rs.getString("name"));
student.setEmail(rs.getString("email"));
student.setAge(rs.getInt("age"));
}
return student; //给了dao方法调用的返回值
多个参数-使用@Param
上述一个简单参数当然也能用param传参
当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”), mapper 文件使用#{自定义参数名}。
接口:
List<Student> selectStudentMultiParam(@Param("myname") String name,@Param("myage")
Integer age);
mapper文件:
<select id="selectStudentMultiParam" resultType="ysk.domain.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>
测试:
@Test
public void testMultiParam(){
SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
List<Student> list = dao.selectStudentMultiParam("刘备", 20);
for (Student student : list) {
System.out.println(student);
}
session.close();
}
多个参数-使用对象
接口:
List<Student> selectStudentMultiObject(QueryParam queryParam);
创建保存参数值的对象 QueryParam:
package ysk.dao.ov;
public class QueryParam {
private String queryName;
private int queryAge;
//get set
}
mapper文件:
<select id="selectStudentMultiObject" resultType="ysk.domain.Student">
select id,name,email,age from student
where name=#{queryName,javaType=string,jdbcType=VARCHAR}
or age =#{queryAge,javaType=int,jdbcType=INTEGER}
</select>
上述情况用的较少,一般这样用:
<select id="selectStudentMultiObject" resultType="ysk.domain.Student">
select id,name,email,age from student
where name=#{queryName}
or age =#{queryAge}
</select>
测试文件:
@Test
public void testMultiObject(){
SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
QueryParam queryParam = new QueryParam();
queryParam.setQueryAge(20);
queryParam.setQueryName("zhangsan");
List<Student> list = dao.selectStudentMultiObject(queryParam);
for (Student student : list) {
System.out.println(student);
}
session.close();
}
注意:可以灵活一点,QueryParam可以不创建,直接用student类也可以
多个参数-按位置
不推荐使用!
参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1} 注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。
接口:
List<Student> selectByNameAndAge(String name,int age);
mapper文件:
<select id="selectByNameAndAge" resultType="ysk.domain.Student">
select id,name,email,age from student where name=#{arg0} or age =#{arg1}
</select>
测试文件:
//按位置参数
List<Student> stuList = dao.selectByNameAndAge("李四",20);
for (Student student : stuList) {
System.out.println(student);
}
多个参数-使用 Map
不推荐使用!
Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key, Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值。
接口:
List<Student> selectMultiMap(Map<String,Object> map);
mapper文件:
<select id="selectMultiMap" resultType="ysk.domain.Student">
select id,name,email,age from student where name=#{myname} or age =#{myage}
</select>
测试:
@Test
public void testSelectMultiMap(){
Map<String,Object> data = new HashMap<>();
data.put("myname","李力");// #{myname}
data.put("myage",20); // #{myage}
List<Student> stuList = studentDao.selectMultiMap(data);
stuList.forEach( stu -> System.out.println(stu));
}
# 和 $ 的区别
-
select id,name, email,age from student where id = #{id}
结果是:select id,name, email,age from student where id =?
-
$
select id,name, email,age from student where id = ${id}
结果是:select id,name, email,age from student where id =1001
两者的区别:
- #:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“?”。这样做更安全(防止sql注入),更迅速,通常也是首选做法,
- $ :字符串替换,告诉 mybatis 使用 $包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的 内容连接起来。主要用在替换表名,列名,不同列排序等操作。
替换列名或表名时用$:
接口:
Student findByDiffField(@Param("col") String colunName,@Param("cval") Object value);
mapper文件:
<select id="findByDiffField" resultType="ysk.domain.Student">
select * from student where ${col} = #{cval}
</select>
测试:
Student student1 = dao.findByDiffField("id",1002);
System.out.println("按 id 列查询:"+student1);
Student student2 = dao.findByDiffField("email","[email protected]");
System.out.println("按 email 列查询:"+student2);
封装mybatis输出结果
resultType
mybatis执行了sql语句,得到java对象
mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象,mybatis把ResultSet指定列值付给同名的属性
mapper文件:
<select id="selectMultiPosition" resultType="ysk.domain.Student">
select id,name, email,age from student
</select>
对应:
ResultSet rs = executeQuery(" select id,name, email,age from student" );
while(rs.next()){
Student student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"))
}
框架的处理: 使用构造方法创建对象。调用 setXXX 给属性赋值。
Student student = new Student();
sql 语句列 | java 对象方法 | |
---|---|---|
id | setId( rs.getInt(“id”) ) | 调用列名对应的 set 方法 id 列 — setId() name 列 — setName() |
name | setName( rs.getString(“name”) ) | …… |
setEmail( rs.getString(“email”) ) | …… | |
age | setAge( rs.getInt(“age”) ) | …… |
注意:Dao 接口方法返回是集合类型,需要指定集合中的类型,不是集合本身。
别名
在mybatis.xml配置文件中定义别名的配置
两种方式:
-
一个类型一个别名
type:自定义类型的全限定名称
alias: 别名
<typeAliases> <typeAlias type="ysk.domain.Student" alias="stu" /> </typeAliases>
-
<package>
name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)<typeAliases> <package name="ysk.domain"/> <package name="ysk.vo"/> </typeAliases>
比较推荐使用的还是全限定名称(ysk.domain.Student),第二种定义别名的方式不推荐使用,可能不同包中有相同的类名导致报错!
返回值是map类型:
有限制条件:只能最多返回一行记录。超过一行就是错误!
接口:
//定义方法返回Map
Map<Object,Object> selectMapById(Integer id);
mapper文件:
<!--返回Map
1)列名是map的key, 列值是map的value
2)只能最多返回一行记录。多余一行是错误
-->
<select id="selectMapById" resultType="java.util.HashMap">
select id,name,email from student where id=#{stuid}
</select>
测试:
Map<Object,Object> map = dao.selectMapById(1001);
System.out.println("map=="+map);
resultMap,列名和属性名不一致的两种解决方式
列名和属性名不一样,第一种方式:
mapper 文件:
<!--定义resultMap
id:自定义名称,表示你定义的这个resultMap
type:java类型的全限定名称
-->
<resultMap id="studentMap" type="ysk.domain.Student">
<!--列名和java属性的关系-->
<!--注解列,使用id标签
column :列名
property:java类型的属性名
-->
<id column="id" property="id" />
<!--非主键列,使用result-->
<result column="name" property="name" />
<result column="email" property="email" />
<result column="age" property="age" />
</resultMap>
<select id="selectAllStudents" resultMap="studentMap">
select id,name, email , age from student
</select>
测试:
List<Student> student = dao.selectStudents();
for (Student student1 : student) {
System.out.println(student1);
}
session.close();
resultMap是比较常用的,数据库字段和实体类属性名不对应的经常使用。
第二种方式:
使用resultType的属性,之后再定义的时候通过数据库名 id查询 映射到实体类中的的结果 进行辨别
<!--列名和属性名不一样:第二种方式
resultType的默认原则是 同名的列值赋值给同名的属性, 使用列别名(java对象的属性名)
-->
<select id="selectDiffColProperty" resultType="ysk.domain.MyStudent">
select id as stuid ,name as stuname, email as stuemail , age stuage from student
</select>
模糊like
第一种方式,推荐使用:
接口:
List<Student> selectStudentLikeOne(String name);
mapper文件:
<select id="selectStudentLikeOne" resultType="ysk.domain.Student">
select id,name,email,age from student where name like #{name}
</select>
测试:
String name = "%尚%";
List<Student> student = dao.selectStudentLikeOne(name);
for (Student student1 : student) {
System.out.println(student1);
}
session.close();
第二种方式:
接口:
List<Student> selectLikeTwo(String name);
mapper文件:
"%" #{name} "%"
中间一定要带空格
<!--第二种方式:在mapper文件中拼接 like的内容-->
<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name like "%" #{name} "%"
</select>
测试:
String name = "张";
List<Student> students = dao.selectLikeTwo(name);
for(Student stu: students){
System.out.println("*******学生="+stu);
}
sqlSession.close();
动态sql
if结构
对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。 语法: sql 语句的部分
mapper文件:
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
select id,name, age, email from student
where
<if test="name !=null and name !='' ">
name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</select>
接口:
List<Student> selectStudent(Student student);
mapper文件:
<resultMap id="studentMap" type="ysk.domain.Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="age" property="age"/>
</resultMap>
<select id="selectStudent" resultMap="studentMap">
select id,name,email,age from student where
<if test="name != null and name !=''">
name = #{name}
</if>
<if test="age > 20">
age = #{age}
</if>
</select>
这种写法可能会导致错误,当姓名不满足要求时,sql语句变成where or age>20,sql语法错误!可在where后面加上1=1 避免这种错误!
测试:
Student student = new Student();
student.setName("李四");
student.setAge(18);
List<Student> list = dao.selectStudent(student);
for (Student student1 : list) {
System.out.println(student1);
}
session.close();
where结构
语法:<where> 其他动态 sql </where>
mapper文件:
<select id="selectStudentWhere" resultType="ysk.domain.Student">
select id,name, age, email from student
<where>
<if test="name !=null and name !='' ">
name = #{name}
</if>
<if test="age > 0">
or age > #{age}
</if>
</where>
</select>
至少有一个if条件成立时where标签才会起作用,当or或者and多余时会自动将它去掉!
foreach
语法:
<foreach collection="集合类型" open="开始的字符" close="结束的字符"
item="集合中的成员" separator="集合成员之间的分隔符">
#{item 的值}
</foreach>
遍历 List<简单类型>
接口:
List<Student> selectStudentForList(List<Integer> idList);
拼接sql测试:
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
String sql = "select * from student where id in ";
StringBuilder builder = new StringBuilder();
builder.append("(");
for (Integer integer : list) {
builder.append(integer).append(",");
}
builder.deleteCharAt(builder.length()-1); //删除最后一个逗号
builder.append(")");
sql+=builder.toString();
System.out.println(sql); //select * from student where id in (1001,1002,1003)
mapper文件:
<select id="selectForeachOne" resultType="ysk.domain.Student">
select id,name,email,age from student where id in
<foreach collection="list" item="myid" open="(" close=")" separator=",">
#{myid}
</foreach>
</select>
测试文件:
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
List<Student> stu = dao.selectForeachOne(list);
for (Student student : stu) {
System.out.println(student);
}
遍历 List<对象类型>
接口:
List<Student> selectForeachTwo(List<Student> stulist);
mapper文件:
<select id="selectForeachTwo" resultType="ysk.domain.Student">
select * from student where id in
<foreach collection="list" item="stu" open="(" close=")" separator=",">
#{stu.id}
</foreach>
</select>
测试文件:
List<Student> list = new ArrayList<>();
Student s1 = new Student();
s1.setId(1002);
s1.setName("lisi");
list.add(s1);
Student s2 = new Student();
s1.setId(1001);;
s1.setName("zs");
list.add(s1);
List<Student> list1 = dao.selectForeachTwo(list);
for (Student student : list1) {
System.out.println(student);
}
代码片段
<sql/>
标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用 <include/>
子标签。该<sql/>
标签可以定义 SQL 语句中的任何部分,所以<include/>
子标签可以放在动态 SQL 的任何位置。
简而言之就是定义了之后在其它地方可以使用,达到代码的复用。
<!--创建 sql 片段 id:片段的自定义名称-->
<sql id="studentSql">
select id,name,email,age from student
</sql>
<select id="selectStudentSqlFragment"
resultType="com.bjpowernode.domain.Student">
<!-- 引用 sql 片段 -->
<include refid="studentSql"/>
<if test="list !=null and list.size > 0 ">
where id in
<foreach collection="list" open="(" close=")"
item="stuobject" separator=",">
#{stuobject.id}
</foreach>
</if>
</select>
mybatis配置文件
主配置文件
之前项目中使用的 mybatis.xml 是主配置文件。 主配置文件特点:
-
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>
-
主要包含内容:
- 定义别名
- 数据源
- mapper文件
dataSource 标签
Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的 mybatis.xml 配置文件中,通过<dataSource type=”pooled”>
来实现 Mybatis 中连接池的配置。
dataSource 类型
Mybatis 将数据源分为三类:
- UNPOOLED 不使用连接池的数据源
- POOLED 使用连接池的数据源
- JNDI 使用 JNDI 实现的数据源
其中 UNPOOLED ,POOLED 数据源实现了 javax.sq.DataSource 接口, JNDI 和前面两个实现方式不同,了解 可以。
dataSource 配置
在 MyBatis.xml 主配置文件,配置 dataSource:
<dataSource type="POOLED">
<!--连接数据库的四个要素-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/ssm?charset=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,即: type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例 type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
使用数据库属性配置文件
为了方便对数据库连接的管理,DB 连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis 主配置文件需要从这个属性文件中读取这些数据
-
在 classpath 路径下,创建 properties 文件
在 resources 目录创建 jdbc.properties 文件,文件名称自定义。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/springdb jdbc.user=root jdbc.passwd=123
-
使用 properties 标签
修改主配置文件,文件开始位置加入:
<?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文件的位置,从类路径根开始找文件--> <properties resource="jdbc.properties" />
-
使用 key 指定值
<environments default="mydev"> <environment id="mydev"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!--使用 properties 文件: 语法 ${key}--> <!--数据库的驱动类名--> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.user}"/> <property name="password" value="${jdbc.passwd}"/> </dataSource> </environment> </environments>
mappers(映射器)
-
指定多个mapper文件
<!-- sql mapper(sql映射文件)的位置--> <mappers> <mapper resource="com/bjpowernode/dao/StudentDao.xml"/> <mapper resource="com/bjpowernode/dao/OrderDao.xml" /> </mappers>
-
使用包名
注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中!
这个包中所有xml文件一次都能加载给mybatis
<!-- sql mapper(sql映射文件)的位置--> <mappers> <package name="com.bjpowernode.dao"/> <!-- <package name="com.bjpowernode.dao2"/> <package name="com.bjpowernode.dao3"/>--> </mappers>
PageHelper
分页功能
-
maven坐标
<!--PageHelper依赖--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency>
-
加入 plugin 配置
在<environments>之前加入
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor" /> </plugins>
-
PageHelper 对象
测试方法:
@Test public void testSelect() throws IOException { //加入PageHelper的方法,分页 // pageNum: 第几页, 从1开始 // pageSize: 一页中有多少行数据 PageHelper.startPage(1,3); List<Student> studentList = studentDao.selectStudents(); studentList.forEach( stu -> System.out.println(stu)); }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。