junit
junit
4.11
test
org.mybatis
mybatis
3.5.1
mysql
mysql-connector-java
5.1.9
src/main/java
**/*.properties
**/*.xml
false
public class Student {
//属性名和列名一样
private Integer id;
private String name;
private String email;
private Integer age;
// set , get , toString
}
public interface StudentDao {
/查询所有数据/
List selectStudents();
}
<?xml version="1.0" encoding="UTF-8" ?>select id,name,email,age from student
<?xml version="1.0" encoding="UTF-8" ?>@Test
public void testMyBatis() throws IOException {
//1.mybatis 主配置文件
String config = “mybatis-config.xml”;
//2.读取配置文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建 SqlSessionFactory 对象,目的是获取 SqlSession
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//4.获取 SqlSession,SqlSession 能执行 sql 语句
SqlSession session = factory.openSession();
//5.执行 SqlSession 的 selectList()
List studentList =
session.selectList(“com.xxx.dao.StudentDao.selectStudents”);//namespace + id
//6.循环输出查询结果
studentList.forEach( student -> System.out.println(student));
//7.关闭 SqlSession,释放资源
session.close();
}
MyBatis配置文件
-
dataSource 标签
-
dataSource 类型
-
UNPOOLED: 不使用连接池的数据源
-
POOLED: 使用连接池的数据源
-
JNDI: 使用 JNDI 实现的数据源
其中 UNPOOLED ,POOLED 数据源实现了 javax.sq.DataSource 接口,
JNDI 和前面两个实现方式不同,了解就可以。
- dataSource 配置
-
事务
-
默认需要手动提交事务
-
Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection对象的 commit(), rollback()
Connection 对象的 setAutoCommit()方法来设置事务提交方式的。自动提交和手工提交。 -
-
JDBC:使用 JDBC 的事务管理机制。即通过 Connection 的 commit()方法提交,通过 rollback()方法回滚。
但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对事务进行提交或回滚。
-
MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)
-
自动提交事务
-
设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。
有参数为 true,使用自动提交 session = factory.openSession(true)
-
使用数据库属性配置文件【properties文件】(解耦合)
-
为了方便对数据库连接的管理,DB 连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis主配置文件需要从这个属性文件中读取这些数据。
-
在 classpath 路径下,创建 properties 文件
-
在 resources 目录创建 jdbc.properties 文件,文件名称自定义。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?charset=utf-8
jdbc.username=root
jdbc.password=root
- 使用 properties 标签
<–!使用properties标签–/>
- 使用 key 指定值
-
mappers【映射器】
-
< mapper resource=" " />
-
使用相对于类路径的资源,从 classpath 路径查找文件
-
< package name=“”/>
-
指定包下的所有 Dao 接口
-
注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中。
创建工具类
public class MyBatisUtil {
//定义 SqlSessionFactory
private static SqlSessionFactory factory = null;
static {
//使用 静态块 创建一次 SqlSessionFactory
try{
String config = “mybatis-config.xml”;
//读取配置文件
InputStream in = Resources.getResourceAsStream(config);
//创建 SqlSessionFactory 对象
factory = new SqlSessionFactoryBuilder().build(in);
} catch (Exception e){
factory = null;
e.printStackTrace();
}
}
/* 获取 SqlSession 对象 */
public static SqlSession getSqlSession(){
SqlSession session = null;
if( factory != null){
session = factory.openSession();
}
return session;
}
}
DAO开发
(1)创建 Dao 接口实现类
public class StudentDaoImpl implements StudentDao
(2)实现接口中 select 方法
public List selectStudents() {
SqlSession session = MyBatisUtil.getSqlSession();
List studentList = session.selectList(
“com.xxx.dao.StudentDao.selectStudents”);
session.close();
return studentList;
}
测试查询操作:
// MyBatisTest 类中创建 StudentDaoImpl 对象
public class MyBatisTest {
@Test
public void testSelect() throws IOException {
StudentDao studentDao = new StudentDaoImpl();
List studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
}
在前面例子中自定义 Dao 接口实现类时发现一个问题:
Dao 的实现类其实并没有干什么实质性的工作,
它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,
真正对 DB 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。
所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,
对DB 进行操作。
这种对 Dao 的实现方式称为 Mapper 的动态代理方式。
Mapper 动态代理方式无需程序员实现 Dao 接口。
接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。
我们不再需要编写DAO接口的实现类,只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定 Dao接口类的 class 值。
StudentDao studentDao = MyBatisUtil.getSqlSession().getMapper(StudentDao.class);
使用DAO代理对象执行sql语句
select 方法:
@Test
public void testSelect() throws IOException {
List studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
}
insert 方法:
@Test
public void testInsert() throws IOException {
Student student = new Student();
student.setId(1006);
student.setName(“林浩”);
student.setEmail(“linhao@163.com”);
student.setAge(26);
int nums = studentDao.insertStudent(student);
System.out.println(“使用 Dao 添加数据:”+nums);
}
update 方法
@Test
public void testUpdate() throws IOException {
Student student = new Student();
student.setId(1006);
student.setAge(28);
int nums = studentDao.updateStudent(student);
System.out.println(“使用 Dao 修改数据:”+nums);
}
delete 方法
@Test
public void testDelete() throws IOException {
int nums = studentDao.deleteStudent(1006);
System.out.println(“使用 Dao 修改数据:”+nums);
}
原理
这里解释了上面为什么要推荐namespace的值写为: dao接口的全限定名称
id的值写为:dao 接口中方法名称
只有这样MyBatis才能准确的知道你要执行的sql语句是什么
JDK的动态代理
parameterType:
接口中的方法参数的类型, Java的数据类型的全限定名称或MyBatis定义的别名。
这个属性是可选的,因为 MyBatis通过反射机制能够发现接口方法参数的类型。
MyBatis 传递参数
一个简单类型的参数:
简单类型:MyBatis把基本数据类型和String都叫做简单类型。
使用:#{任意字符},和方法的参数无关。
使用#{}之后,MyBatis执行sql语句使用的是PreparedStatement对象。
关于PreparedStatement对象的使用,可以看这篇博客
多个参数:
- 使用@param
在方法形参前面加入@Param(“自定义参数名”),mapper 文件使用#{自定义参数名}。
接口方法:
List selectMultiParam(@Param(“personName”) String name,
@Param(“personAge”) int age);
mapper 文件:
select id,name,email,age from student where name= #{personName} or
age= #{personAge}
- 使用对象
使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。
语法格式: #{ property, javaType=java 中数据类型名, jdbcType=数据类型名称 }
javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property 【对象的属性名】}
- 按位置(了解)
参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1}
注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。
- 使用Map(了解)
Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key,
Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值。
例如:
Map<String,Object> data = new HashMap<String,Object>();
data.put(“myname”,”xxx");
data.put(“myage”,20);
接口方法:
List selectMultiMap(Map<String,Object> map);
mapper 文件:
select id,name,email,age from student where name=#{myname} or age =#{myage}
**#**和$
#:占位符,告诉 mybatis 使用实际的参数值代替。并使用PrepareStatement对象执行 sql 语句,
#{…}代替sql 语句的“?”。这样做更安全【能避免sql注入】,更迅速,效率高,通常也是首选做法。
** ∗ ∗ 【 ∗ ∗ 字 符 串 替 换 ∗ ∗ 】 : 告 诉 m y b a t i s 使 用 ** 【**字符串替换**】:告诉 mybatis 使用 ∗∗【∗∗字符串替换∗∗】:告诉mybatis使用包含的"字符串"替换所在位置。使用Statement把sql语句
和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。
但是具有sql注入的风险。详见这篇博客
定义别名
<–!在mybatis.xml主配置文件定义别名–>
resultType
执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。 注意如果返回的是集合,
那应该设置为集合中的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。
- 简单类型
// 接口方法:
int countStudent();
mapper 文件:
select count(*) from student
// 测试方法:
@Test
public void testRetunInt(){
int count = studentDao.countStudent();
System.out.println(“学生总人数:”+ count);
}
-
对象类型
-
处理方法:
-
MyBatis执行sql语句,然后调用类的无参构造方法,创建对象。
-
MyBatis把ResultSet指定的列值赋值给同名的属性名。
-
Map
sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map<Object,Object>。
注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。
resultMap
resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。
常用在列名和 java 对象属性名不一样的情况。
使用方式:
1.先定义 resultMap,指定列名和属性的对应关系。
2.在中把 resultType 替换为 resultMap。
列名和属性名不一样的解决方案
第一 种方式:使用resultMap
public class PrimaryStudent {
private Integer stuId;
private String stuName;
private Integer stuAge;
// set , get 方法
}
select id,name,email,age from student
第二种方式:使用列别名
select id as stuId, name as stuName,age as stuAge from student
模糊查询的实现有两种方式, 一是 java 代码中给查询数据加上“%” ; 推荐
二是在 mapper 文件 sql 语句的条件位置加上“%”
方法一:
// 需求:查询姓名有“力”的
// 接口方法:
List selectLikeFirst(String name);
mapper文件:
select id,name,email,age from student
where name like #{studentName}
// 测试方法:
@Test
public void testSelectLikeOne(){
String name=“%力%”;
List stuList = studentDao.selectLikeFirst(name);
stuList.forEach( stu -> System.out.println(stu));
}
方法二:
// 接口方法:
List selectLikeSecond(String name);
mapper 文件:
select id,name,email,age from student
where name like “%” #{studentName} “%”
// 测试方法:
@Test
public void testSelectLikeSecond(){
String name=“力”;
List stuList = studentDao.selectLikeSecond(name);
stuList.forEach( stu -> System.out.println(stu));
}
动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。
提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,
将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题
动态 SQL 之< if >
对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。
语法:< if test=“条件” > sql 语句的部分 < /if >
select id,name,email,age from student
where 1=1
and name = #{name}
and age > #{age}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。
提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,
将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题
动态 SQL 之< if >
对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。
语法:< if test=“条件” > sql 语句的部分 < /if >
select id,name,email,age from student
where 1=1
and name = #{name}
and age > #{age}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-rAQC7OOd-1715831710875)]
[外链图片转存中…(img-fc0XtmJl-1715831710876)]
[外链图片转存中…(img-MdIBqFOS-1715831710876)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!