
界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。
(jsp ,html ,servlet)
业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等的。
- 三层对应的包
- 界面层: controller包 (servlet)
- 业务逻辑层: service 包(XXXService类)
- 数据访问层: dao包(XXXDao类)
- 三层中类的交互
- 用户使用界面层–> 业务逻辑层—>数据访问层(持久层)–>数据库(mysql)
- 三层对应的处理框架
-
界面层—servlet—springmvc(框架)
-
业务逻辑层—service类–spring(框架)
-
数据访问层—dao类–mybatis(框架)
框架是一个舞台, 一个模版
1.2.1 模版- 规定了好一些条款,内容。
- 加入自己的东西
1.框架中定义好了一些功能。
这些功能是可用的。
2.可以加入项目中自己的功能, 这些功能可以利用框架中写好的功能。
1.2.3 框架特点框架是一个软件,半成品的软件,定义好了一些基础功能, 需要加入你的功能就是完整的。
基础功能是可重复使用的,可升级的。
- 框架一般不是全能的, 不能做所有事情
- 框架是针对某一个领域有效。
特长在某一个方面,比如mybatis做数据库 *** 作强,但是他不能做其它的。
- 框架是一个软件
mybatis框架,早期叫做ibatis, 代码在github。
mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)
1)sql mapper :sql映射
可以把数据库表中的一行数据 映射为 一个java对象。
一行数据可以看做是一个java对象。
*** 作这个对象,就相当于 *** 作表中的数据
2) Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。
mybatis提供了哪些功能:
-
提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了
-
提供了执行sql语句的能力, 不用你执行sql
-
提供了循环sql, 把sql的结果转为java对象, List集合的能力
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); } -
提供了关闭资源的能力,不用你关闭Connection, Statement, ResultSet
开发人员做的是: 提供sql语句
最后是: 开发人员提供sql语句–mybatis处理sql—开发人员得到List集合或java对象(表中的数据)
- 代码比较多,开发效率低
- 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
- 对 ResultSet 查询的结果,需要自己封装为 List
- 重复的代码比较多些
- 业务代码和数据库的 *** 作混在一起
mybatis是一个sql映射框架,提供的数据库的 *** 作能力。
增强的JDBC,使用mybatis让开发人员集中精神写sql就可以了,不必关心Connection,Statement,ResultSet的创建,销毁,sql的执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gxdUVvTt-1648717794817)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329210206197.png)]
2.1 实现步骤 2.1.1 创建student数据库表[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g8CVNx60-1648717794819)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329210359947.png)]
2.1.2加入maven的坐标和插件
<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.0modelVersion>
<groupId>com.bjpowernodegroupId>
<artifactId>ch01-hello-mybatisartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.9version>
dependency>
dependencies>
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
project>
2.1.3创建实体类
package com.bjpowernode.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 +
'}';
}
}
2.1.4创建持久层dao接口
package com.bjpowernode.dao;
import com.bjpowernode.domain.Student;
import java.util.List;
//接口 *** 作student表
public interface StudentDao {
//查询student表的所有的数据
public List<Student> selectStudents();
//插入方法
//参数: student ,表示要插入到数据库的数据
//返回值: int , 表示执行insert *** 作后的 影响数据库的行数
public int insertStudent(Student student);
}
2.1.5创建mybatis的配置文件
叫做sql映射文件:写sql语句的。
一般一个表一个sql映射文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.StudentDao">
<select id="selectStudents" resultType="com.bjpowernode.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>
2.1.6创建mybatis的主配置文件
一个项目就一个主配置文件。
主配置文件提供了数据库的连接信息和sql映射文件的位置信息。
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
settings>
<environments default="mydev">
<environment id="mydev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
<environment id="online">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/onlinedb"/>
<property name="username" value="root"/>
<property name="password" value="fhwertwr"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
mappers>
configuration>
2.1.7创建测试类
package com.bjpowernode;
import com.bjpowernode.domain.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.IOException;
import java.io.InputStream;
import java.util.List;
public class MyApp {
public static void main(String[] args) throws IOException {
//访问mybatis读取student数据
//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/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";
String sqlId = "com.bjpowernode.dao.StudentDao.selectStudents";
//7.【重要】执行sql语句,通过sqlId找到语句
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();
}
}
2.1.8配置日志功能
mybatis.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
settings>
效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qth5Fgrk-1648717794821)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329211740321.png)]
2.2 主要类的介绍 2.2.1Resources: mybatis中的一个类, 负责读取主配置文件
InputStream in = Resources.getResourceAsStream(“mybatis.xml”);
创建SqlSessionFactory对象,
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。
在整个项目中,有一个就够用了。
SqlSessionFactory:接口 , 接口实现类: DefaultSqlSessionFactory
SqlSessionFactory作用: 获取SqlSession对象。
SqlSession sqlSession = factory.openSession();
openSession()方法说明:
1. openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
- openSession(boolean): openSession(true) 获取自动提交事务的SqlSession.
openSession(false) 非自动提交事务的SqlSession对象
SqlSession接口 :定义了 *** 作数据的方法 例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
SqlSession接口的实现类DefaultSqlSession。
使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。
在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。
这里有一个问题,我们从始至终都没有用到Dao接口类,我们现在来用传统的Dao实现类来使用Dao接口
2.3mybatis使用传统dao开发方式 2.3.1创建持久层dao接口package com.bjpowernode.dao;
import com.bjpowernode.domain.Student;
import java.util.List;
public interface StudentDao {
List<Student> selectStudents();
int insertStudent(Student student);
}
2.3.2创建dao接口实现类
package com.bjpowernode.dao.impl;
import com.bjpowernode.dao.StudentDao;
import com.bjpowernode.domain.Student;
import com.bjpowernode.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List;
public class StudentDaoImpl implements StudentDao {
@Override
public List<Student> selectStudents() {
//获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
String sqlId="com.bjpowernode.dao.StudentDao.selectStudents";
//执行sql语句, 使用SqlSession类的方法
List<Student> students = sqlSession.selectList(sqlId);
//关闭
sqlSession.close();
return students;
}
@Override
public int insertStudent(Student student) {
//获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
String sqlId="com.bjpowernode.dao.StudentDao.insertStudent";
//执行sql语句, 使用SqlSession类的方法
int nums = sqlSession.insert(sqlId,student);
//提交事务
sqlSession.commit();
//关闭
sqlSession.close();
return nums;
}
}
2.3.3测试类
package com.bjpowernode;
import com.bjpowernode.dao.StudentDao;
import com.bjpowernode.dao.impl.StudentDaoImpl;
import com.bjpowernode.domain.Student;
import org.junit.Test;
import java.util.List;
public class TestMyBatis {
@Test
public void testSelectStudents(){
//com.bjpowernode.dao.StudentDao
StudentDao dao = new StudentDaoImpl();
/** 实现原理:
* List studentList = dao.selectStudents(); 调用
* 1.dao对象,类型是StudentDao,全限定名称是:com.bjpowernode.dao.StudentDao
* 全限定名称 和 namespace 是一样的。
*
* 2.方法名称, selectStudents, 这个方法就是 mapper文件中的 id值 selectStudents
*
* 3.通过dao中方法的返回值也可以确定MyBatis要调用的SqlSession的方法
* 如果返回值是List ,调用的是SqlSession.selectList()方法。
* 如果返回值 int ,或是非List的, 看mapper文件中的 标签是, 就会调用
* SqlSession的insert, update等方法
*
* mybatis的动态代理: mybatis根据 dao的方法调用,获取执行sql语句的信息。
* mybatis根据你的dao接口,创建出一个dao接口的实现类, 并创建这个类的对象。
* 完成SqlSession调用方法, 访问数据库。
*
*/
List<Student> studentList = dao.selectStudents();
for(Student stu:studentList){
System.out.println(stu);
}
}
@Test
public void testInsertStudent(){
StudentDao dao = new StudentDaoImpl();
Student student = new Student();
student.setId(1005);
student.setName("盾山");
student.setEmail("dunshan@qq.com");
int nums = dao.insertStudent(student);
System.out.println("添加对象的数量:"+nums);
}
}
2.2.4工具类
package com.bjpowernode.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);
//创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
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;
}
}
2.4 传统 Dao 开发方式的分析
在前面例子中自定义 Dao 接口实现类时发现一个问题:Dao 的实现类其实并没有干什么实质性的工 作,它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进 行 *** 作的工作其实是由框架通过 mapper 中的 SQL 完成的。
所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对 DB 进行 *** 作。
这种对 Dao 的实现方式称为 Mapper 的动态代理方式。
Mapper 动态代理方式无需程序员实现 Dao 接口。
接口是由 MyBatis 结合映射文件自动生成的动态代 理实现的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKiHu7id-1648717794822)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329214821252.png)]
由于用到了动态代理,所以,我们不需要创建Dao的接口实现类,直接交给代理来生成Dao的接口实现类。
动态代理: 使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象
3.1.2 getMapper获取代理对象package com.bjpowernode;
import com.bjpowernode.dao.StudentDao;
import com.bjpowernode.domain.Student;
import com.bjpowernode.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import java.util.List;
public class TestMyBatis {
@Test
public void testSelectStudents(){
/**
* 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
* getMapper能获取dao接口对于的实现类对象。
*/
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//com.sun.proxy.$Proxy2 : jdk的动态代理
System.out.println("dao="+dao.getClass().getName());
//调用dao的方法, 执行数据库的 *** 作
List<Student> students = dao.selectStudents();
for(Student stu: students){
System.out.println("学生="+stu);
}
}
@Test
public void testInsertStudent(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1007);
student.setName("李飞");
student.setEmail("dunshan@qq.com");
student.setAge(28);
int nums = dao.insertStudent(student);
sqlSession.commit();
System.out.println("添加对象的数量:"+nums);
}
}
3.2 深入理解参数
3.2.1 parameterType
parameterType : dao接口中方法参数的数据类型。
parameterType它的值是java的数据类型全限定名称或者是mybatis定义的别名
例如:parameterType=“java.lang.Integer”
parameterType=“int”
int 或 java.lang.Integer
hashmap 或 java.util.HashMap
list 或 java.util.ArrayList
student 或 com.bjpowernode.domain.Student
注意:默认值为未设置(unset)。
接口中方法的参数从 java 代码传入到 mapper 文件的 sql 语句。
parameterType不是强制的,mybatis通过反射机制能够发 现接口参数的数类型。
所以可以没有。
一般我们也不写。
当传递的参数只有一个的时候:多个则不能使用这个属性
<select id="selectStudentById" parameterType="int" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where id=${studentId}
select>
3.2.2 MyBatis 传递参数
1.一个简单参数
Dao 接口中方法的参数只有一个简单类型(java 基本类型和 String),占位符 #{ 任意字符 },和方法的参数名无关。
与传入的对象无关,与传入的值有关。
单个参数传递给sql语句时不需要用命名参数,否则就需要使用命名参数。
接口:
/**
* 一个简单类型的参数:
* 简单类型: mybatis把java的基本数据类型和String都叫简单类型。
* 在mapper文件获取简单类型的一个参数的值,使用 #{任意字符}
*/
public Student selectStudentById(@Param("studentId") Integer id);
mapper:
<select id="selectStudentById" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where id=#{studentId}
select>
#{studentId} , studentId 是自定义的变量名称,和方法参数名无关。
2.多个参数-使用@Param
当 Dao 接口方法多个参数,需要通过名称使用参数。
在方法形参前面加入@Param(“自定义参数名”), mapper 文件使用#{自定义参数名}。
接口:
/**
* 多个参数: 命名参数,在形参定义的前面加入 @Param("自定义参数名称")
*/
List<Student> selectMultiParam(@Param("myname") String name,
@Param("myage") Integer age);
mapper:
<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where name=#{myname} or age=#{myage}
select>
3.多个参数-使用对象
-
vo: value object , 放一些存储数据的类。
比如说 提交请求参数, name ,age 现在想把name ,age 传给一个service 类。
-
vo: view object , 从servlet把数据返回给浏览器使用的类,表示显示结果的类。
-
pojo: 普通的有set, get方法的java类。
普通的java对象
Servlet --- StudentService( addStudent( MyParam param) ) -
entity(domain域): 实体类, 和数据库中的表对应的类,
多个参数, 使用java对象的属性值,作为参数实际值
使用对象语法: #{属性名,javaType=类型名称,jdbcType=数据类型} 很少用。
javaType:指java中的属性数据类型。
jdbcType:在数据库中的数据类型。
例如: #{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
我们使用常用的的简化方式:#{属性名} ,javaType, jdbcType的值mybatis反射能获取。
不用提供。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KbqZTtdA-1648717794825)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329225921187.png)]
接口:
/**
* 多个参数,使用java对象作为接口中方法的参数
*/
List<Student> selectMultiObject(QueryParam param);
mapper:
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where
name=#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
or age=#{paramAge,javaType=java.lang.Integer,jdbcType=INTEGER}
select>
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where
name=#{paramName} or age=#{paramAge}
select>
4.多个参数-按位置
参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1}
接口:
/**
* 多个参数-简单类型的,按位置传值,
* mybatis.3.4之前,使用 #{0} ,#{1}
* mybatis。
3.4之后 ,使用 #{arg0} ,#{arg1}
*/
List<Student> selectMultiPosition( String name,Integer age);
mapper:
<select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where
name = #{arg0} or age=#{arg1}
select>
5.多个参数-使用Map
Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。
Map 集合使用 String的 key, Object 类型的值存储参数。
mapper 文件使用 # { key } 引用参数值。
接口:
/**
* 多个参数,使用Map存放多个值
*/
List<Student> selectMultiByMap(Map<String,Object> map);
mapper:
<select id="selectMultiByMap" resultType="com.bjpowernode.domain.Student">
select id,name, email,age from student where
name = #{myname} or age=#{age1}
select>
6.#和$
#:占位符,告诉 mybatis 使用实际的参数值代替。
并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“?”。
这样做更安全可以防止sql注入,更迅速,通常也是首选做法。
$ 字符串替换,告诉 mybatis 使用
包
含
的
“
字
符
串
”
替
换
所
在
位
置
。
使
用
S
t
a
t
e
m
e
n
t
把
s
q
l
语
句
和
包含的“字符串”替换所在位置。 使用 Statement 把 sql 语句和
主要用在:替换表名,列名,不同列排序等 *** 作。
可以替换表名或者列名, 你能确定数据是安全的。
<select id="selectUse$" resultType="com.bjpowernode.domain.Student">
select * from student where name=${myname}
select>
<!--使用 #{}-->
<select id="selectUse" resultType="com.bjpowernode.domain.Student">
select * from student where name=#{myname}
</select>
在日志中看到select语句是有?占位符出现的,这就说明,mybatis底层是调用执行对象preparedStatement对象。
实际上一个#{}就是对应着在底层的JDBC中的一个?号占位符
转为 MyBatis 的执行是: String sql=” select id,name,email,age from student where id=?”;
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,1005);
select id,name, email,age from student where id=#{studentId}
# 的结果: select id,name, email,age from student where id=?
// String sql="select id,name, email,age from student where id=" + "1001";
// 使用的Statement对象执行sql, 效率比PreparedStatement低。
select id,name, email,age from student where id=${studentId}
$ 的结果:select id,name, email,age from student where id=1001
#和 $区别
1. #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
2. #能够避免sql注入,更安全。
3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
4. $有sql注入的风险,缺乏安全性。
5. $:可以替换表名或者列名
3.2.3 别名的定义
定义自定义类型的别名
- 在mybatis主配置文件中定义,使定义别名
- 可以在resultType中使用自定义别名
定义在mybatis主配置文件当中:
<typeAliases>
<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
<typeAlias type="com.bjpowernode.vo.ViewStudent" alias="vstu" />
typeAliases>
<typeAliases>
<package name="com.bjpowernode.domain"/>
<package name="com.bjpowernode.vo"/>
typeAliases>
3.3 封装Mybatis的输出结果
3.3.1 resultType
resultType结果类型, 指sql语句执行完毕后, 数据转为的java对象, java类型是任意的。
resultType结果类型的它值 1. 类型的全限定名称 2. 类型的别名。
例如 java.lang.Integer别名是int。
处理方式:
1. mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象。
2. mybatis把ResultSet指定列值付给同名的属性。
对等的jdbc
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"))
}
resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。
注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。
resultType 和 resultMap,不能同时使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EwkfdDys-1648717794827)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330213158335.png)]
可以把resultType里面的值,可以看做是接口中方法的返回值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-88vXlepi-1648717794828)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330155940294.png)]
1.简单类型接口:int countStudent();
mapper:
<select id="countStudent" resultType="java.lang.Integer">
select count(*) from student
select>
2.对象类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fHoXwUL8-1648717794829)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330160233384.png)]
接口:
ViewStudent selectViewStudent(int id);
mapper:
<select id="selectViewStudent" resultType="com.gz.vo.ViewStudent" >
select id,name,email,age from student where id=#{id}
select>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LzHw6uNx-1648717794830)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330214240452.png)]
3.Mapsql 的查询结果作为 Map 的 key 和 value。
推荐使用 Map。
注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。
大于一条记录是错误。
//定义方法返回Map
Map<Object,Object> selectMapById(Integer id);
<select id="selectMapById" resultType="java.util.HashMap">
select id,name,email from student where id=#{stuid}
select>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0j3PqWPK-1648717794832)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330214507029.png)]
3.3.2 resultMapresultMap:结果映射, 指定列名和java对象的属性对应关系。
1)你自定义列值赋值给哪个属性
2)当你的列名和属性名不一样时,一定使用resultMap resultMap和resultType不要一起用,二选一
resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。
更灵活的把列值赋值给指定属性。
常用在列名和 java 对象属性名不一样的情况。
使用方式: 1.先定义 resultMap,指定列名和属性的对应关系。
2.在中把 resultType 替换为 resultMap。
接口:
/*
* 使用resultMap定义映射关系
* */
List<Student> selectAllStudents();
mapper:
<resultMap id="studentMap" type="com.bjpowernode.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="selectAllStudents" resultMap="studentMap">
select id,name, email , age from student
select>
当数据库列名和 java 对象属性名不一样的情况下:
<resultMap id="myStudentMap" type="com.bjpowernode.domain.MyStudent">
<id column="id" property="stuid" />
<result column="name" property="stuname" />
<result column="email" property="stuemail" />
<result column="age" property="stuage" />
resultMap>
<select id="selectMyStudent" resultMap="myStudentMap">
select id,name, email , age from student
select>
3.3.3 实体类属性名和列名不同的处理方式
步骤:
创建新的实体类 PrimaryStuden
package com.gz.entity;
public class PrimaryStudent {
private Integer stuid;
private String stuname;
public PrimaryStudent() {
}
@Override
public String toString() {
return "PrimaryStudent{" +
"stuid=" + stuid +
", stuname='" + stuname + '\'' +
'}';
}
public Integer getStuid() {
return stuid;
}
public void setStuid(Integer stuid) {
this.stuid = stuid;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
}
1.使用列别名和resultType
接口方法
List<MyStudent> selectMyStudent();
mapper
<resultMap id="studentMap" type="Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="age" property="age"/>
resultMap>
<select id="studentResultMap" resultMap="studentMap">
select id,name,email,age from student where id = #{id}
select>
2.使用resultMap
<select id="studentResultType" resultType="com.gz.entity.PrimaryStudent">
select id as stuid,name as stuname,email,age from student where id = #{id}
select>
<resultMap id="studentMap1" type="com.gz.entity.PrimaryStudent">
<id column="id" property="stuid"/>
<result column="name" property="stuname"/>
resultMap>
3.使用数据库别名的方式
<select id="studentResultType" resultType="com.gz.entity.PrimaryStudent">
select id as stuid,name as stuname,email,age from student where id = #{id}
select>
3.4 模糊like
模糊查询的实现有两种方式:一是 java 代码中给查询数据加上“%” ;
二是在 mapper 文件 sql 语句的条件位置加上“%”。
mapper
<select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name like #{name}
select>
测试类
@Test
public void testSelectLikeOne(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//准备好like的内容
String name = "%李%";
List<Student> students = dao.selectLikeOne(name);
for(Student stu: students){
System.out.println("#######学生="+stu);
}
sqlSession.close();
}
2.mapper 文件中使用 “%” #{xxx} “%”
mapper
<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name like "%" #{name} "%"
select>
测试类
@Test
public void testSelectLikeTwo(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//准备好like的内容
String name = "张";
List<Student> students = dao.selectLikeTwo(name);
for(Student stu: students){
System.out.println("*******学生="+stu);
}
sqlSession.close();
}
第四章 动态SQL
动态SQL: SQL的内容是变化的,可以根据条件获取到不同的sql语句。
主要是where部分发生变化。
动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行 查询。
提交的查询条件不同,执行的 SQL 语句不同。
若将每种可能的情况均逐一列出,对所有条件进行 排列组合,将会出现大量的 SQL 语句。
此时,可使用动态 SQL 来解决这样的问题。
- 在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等 符号,最好将其转换为实体符号。
否则,XML 可能会出现解析出错问题。
- 在使用动态SQL的使用,接口接收的参数一定要使用对象的方式。
特别是对于小于号(<),在 XML 中是绝不能出现的。
否则解析 mapper 文件会出错。
所以我们要使用实体符号:
| < | 小于 | & lt; |
|---|---|---|
| > | 大于 | & gt; |
| >= | 大于等于 | & gt;= |
| <= | 小于等于 | & lt;= |
对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。
语法:< if test=“条件”> sql 语句的部分 if>
接口:
//动态sql ,使用java对象作为参数
List<Student> selectStudentIf(Student student);
mapper:
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
select id,name, age, email from student
where id > 0
<if test="name !=null and name !='' ">
and name = #{name}
if>
<if test="age > 0">
or age > #{age}
if>
select>
4.3动态SQL之< where >
-
< if >标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。
因为,若 where 后 的所有条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL 出错。
所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。
但当数据量很大时,会 严重影响查询效率。
-
使用标签< where />,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加 where 子句。
需要注意的是,第一个< if />标签中的 SQL 片断,可以不包含 and。
不过,写上 and 也不错, 系统会将多出的 and 去掉。
但其它< if />>中 SQL 片断的 and,必须要求写上。
否则 SQL 语句将拼接出错。
-
语法:< where >其他动态SQL< where />
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
<include refid="studentSql" />
<where>
<if test="name !=null and name !='' ">
name = #{name}
if>
<if test="age > 0">
or age > #{age}
if>
where>
select>
4.4动态SQL之< foreach >
引入:当我们需要动态的给in命令里面添加参数时,我们要这样做
@Test
public void testfor(){
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
//String sql="select * from student where id in (1001,1002,1003)";
String sql="select * from student where id in";
StringBuilder builder = new StringBuilder("");
int init=0;
int len = list.size();
//添加开始的 (
builder.append("(");
for(Integer i:list){
builder.append(i).append(",");
}
builder.deleteCharAt(builder.length()-1);
//循环结尾
builder.append(")");
sql = sql + builder.toString();
System.out.println("sql=="+sql);
}
特别的麻烦,所以我们有了< foreach >标签
在foreach中可以放循环的对象,也可以自定义小括号,用法灵活
- 标签用于实现对于数组与集合的遍历。
主要用在sql的in语句中。
对其使用,需要注意:
➢ collection 表示要遍历的集合类型, list ,array 等。
➢ open、close、separator 为对遍历内容的 SQL 拼接。
- 具体含义:
collection:表示接口中的方法参数的类型, 如果是数组使用array , 如果是list集合使用list
item:自定义的,表示数组和集合成员的变量
open:循环开始是的字符
close:循环结束时的字符
separator:集合成员之间的分隔符
- 对应关系:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MhwesW6o-1648717794833)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331105311586.png)]
第一种用法:遍历 List<简单类型>接口:
//foreach 用法 1
List<Student> selectForeachOne(List<Integer> idlist);
mapper:
<select id="selectForeachTwo" resultType="com.bjpowernode.domain.Student">
select * from student where id in
<foreach collection="list" item="stu" open="(" close=")" separator=",">
#{stu.id}
foreach>
select>
测试:
@Test
public void testSelectForEach(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
List<Student> students = dao.selectForeachOne(list);
for(Student stu:students){
System.out.println("foreach--one ==="+stu);
}
}
第二种用法:遍历 List<对象类型>
接口:
//foreach 用法 2
List<Student> selectForeachTwo(List<Student> stulist);
mapper:
<select id="selectForeachTwo" resultType="com.bjpowernode.domain.Student">
select * from student where id in (
<foreach collection="list" item="stu" >
#{stu.id},
foreach>
-1 )
select>
测试:
@Test
public void testSelectForTwo(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> stuList = new ArrayList<>();
Student s1 = new Student();
s1.setId(1002);
s1.setName("lisi");
stuList.add(s1);
s1 = new Student();
s1.setId(1005);;
s1.setName("zs");
stuList.add(s1);
List<Student> students = dao.selectForeachTwo(stuList);
for(Student stu:students){
System.out.println("foreach--two ==="+stu);
}
}
4.5动态SQL之< sql >
< sql />标签用于定义 SQL 片断,以便其它 SQL 标签复用。
而其它标签使用该 SQL 片断,需要使用< include />子标签。
该< sql />标签可以定义 SQL 语句中的任何部分,所以< include />子标签可以放在SQL的任何位置。
<sql id="studentSql">
select id,name, age, email from student
sql>
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
<include refid="studentSql" />
<where>
<if test="name !=null and name !='' ">
name = #{name}
if>
<if test="age > 0">
or age > #{age}
if>
where>
select>
第五章 MyBatis配置文件
5.1 主配置文件
之前项目中使用的 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" >
- 根元素,< configguration >
主要包含内容:
➢ 定义别名
➢ 数据源
➢ mapper 文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1eV2rnyF-1648717794834)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331164335393.png)]
Mybatis 将数据源分为三类:UNPOOLED 不使用连接池的数据源
POOLED 使用连接池的数据源
JNDI 使用 JNDI 实现的数据源
其中 UNPOOLED ,POOLED 数据源实现了 javax.sq.DataSource 接口, JNDI 和前面两个实现方式不同。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UchdfcpH-1648717794836)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331164518778.png)]
5.2.1 dataSource配置
<dataSource type="POOLED">
<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>
MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,即:
- type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
- type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
- type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
- Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection 对象的 commit(), rollback()
< transactionManager type="JDBC" />
- Connection 对象的 setAutoCommit()方法来设置事务提交方式的。
自动提交和手工提交、 该标签用于指定 MyBatis所使用的事务管理器。
MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。
➢ JDBC:使用 JDBC 的事务管理机制。
即,通过 Connection 的 commit()方法提交,通过 rollback()方法 回滚。
但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。
即程序中需要显式的对 事务进行提交或回滚。
从日志的输出信息中可以看到。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8NV1r14p-1648717794837)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331165228331.png)]
➢ MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。
设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZwYBAlx6-1648717794839)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331165239668.png)]
有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法。
session = factory.openSession(false);
再执行 insert *** 作,无需执行 session.commit(),事务是自动提交的
5.4 使用数据库属性配置文件数据库的属性配置文件: 把数据库连接信息放到一个单独的文件中。
和mybatis主配置文件分开。
目的是便于修改,保存,处理多个数据库的信息。
MyBatis 主配置文件需要从这个属性文件中读取这些数据。
步骤:
5.4.1在 classpath 路径下,创建 properties 文件在 resources 目录创建 jdbc.properties 文件,文件名称自定义。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdb
jdbc.user=root
jdbc.passwd=123456
5.4.2 使用 properties 标签
修改主配置文件,文件开始位置加入:
<properties resource="jdbc.properties" />
5.4.3 使用key值
<dataSource type="POOLED">
<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>
5.5 mappers(映射器)
5.5.1 < mapper resource=" " />
使用相对于类路径的资源,从 classpath 路径查找文件 例如:
<mappers>
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<mapper resource="com/bjpowernode/dao/OrderDao.xml" />
mappers>
5.5.2 < package name=" " />
指定包下的所有 Dao 接口
<mappers>
<package name="com.bjpowernode.dao"/>
<package name="com.bjpowernode.dao2"/>
<package name="com.bjpowernode.dao3"/>
mappers>
注意:此种方法要求Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中。
< mapper >里面填的是路径,而< package >是包名
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)