在文献中看到的framework被翻译为框架
Java常用框架:
框架其实就是对通用代码的苗装,提前写好了一堆接口和类,我们可以在做项目的时候直接引入这些接口和类(引入框架),基于这些现有的接口和类进行开发,可以大大提高开发效率.
框架一般都以jar包的形式存在。(jar包中有class文件以及各种配置文件等。)
SSM三大框架的学习顺序:MyBatis、Spring、SpringMVC
MyBatis是一个持久层框架,负责项目开发中的数据访问层(DAO层)
具体来说,MyBatis提供以下功能和特点,用于实现数据访问层的开发:
SQL映射:MyBatis通过XML配置文件或注解的方式,将SQL语句与Java方法进行映射,实现了对象关系映射(ORM),将数据库操作封装成Java方法调用。
参数绑定:MyBatis支持将Java对象、基本类型和Map等作为参数传递给SQL语句,实现了方便灵活的参数绑定。
结果映射:MyBatis可以将查询结果映射为Java对象或基本类型,并支持关联查询和复杂对象图的映射。
缓存机制:MyBatis提供了一级缓存和二级缓存的支持,能够减少对数据库的频繁访问,提高系统性能。
插件扩展:MyBatis提供了插件机制,允许开发者编写自定义插件,拦截并修改MyBatis的核心行为,实现功能的扩展和定制。
总的来说,MyBatis作为一个优秀的持久层框架,主要负责数据访问层的开发,通过SQL映射、参数绑定和结果映射等功能,简化了与数据库的交互,提高了开发效率和代码的可维护性。
- MyBatis本质上就是对JDBC的封装,通过MyBatis完成CRUD。
- MyBatis在三层架构中负责持久层的,属于持久层框架。
MyBatis框架、Spring框架和Spring MVC框架在项目开发中有一些区别,下面是它们的主要区别:
总的来说,MyBatis框架主要关注数据访问层开发,Spring框架提供了更多的企业级特性和全面的解决方案,而Spring
MVC框架则专注于Web应用程序的开发。在实际项目中,可以根据需求选择合适的框架及其整合方式,以实现高效、灵活和可维护的应用程序开发
ORM图示:
MyBatis框架特点:
会JDBC,MyBatis就可以学
resources目录:
放在这个目录当中的,一般都是资源文件,配置文件。直接放到resources目录下的资源,等同于放到了类的根路径下。
<groupId>com.powernodegroupId>
<artifactId>mybatis-001-introductionartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>jarpackaging>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.10version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.30version>
dependency>
步骤3:编写mybatis核心配置文件:mybatis-config.xml,在resources根目录下新建mybatis-config.xml配置文件
XNL是什么?
它一定是一个配置文件。
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.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource=""/>
mappers>
configuration>
注意:
- 第一:这个文件名不是必须叫做mybatis-config.xml,可以用其他的名字。只是大家都采用这个名字。
- 第二,这个文件存放的位置也不是固定的,可以随意,但一般情况下,会放到类的根路径下。
mybatis-config.xml文件中的配置信息不理解没关系,先把连接数据库的信息修改以下即可。其他的别动。
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car">
<insert id="insertCar">
insert into t_car
(id,car_num,brand,guide_price,produce_time,car_type)
values
(null,'102','丰田mirai',40.30,'2014-10-05','氢能源')
insert>
mapper>
<mapper resource="CarMapper.xml"/>
注意:resource属性会自动从类的根路径下开始查找资源。
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.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="CarMapper.xml"/>
mappers>
configuration>
- SqlSession是专门用来执行SQL语句的,是一个Java程序和数据库之间的一次会话
- 要想获取SqlSession对象,需要先获取SqlSeesionFactory对象,通过SqlSessionFactory工厂来生产SqlSession对象
- 怎么获取SqlSessionFactory对象呢?
- 需要首先获取SqlSessionFactoryBuilder对象
- 通过SqlSessionFactoryBuilder对象的build方法,来获取一个SqlSessionFactory对象
mybatis的核心对象包括:
sqlSessionFactoryBuilder
sqlSessionFactory
sqlsession
sqlSessionFactoryBuilder --> sqlsessionFactory --> sqlSession
package com.powernode.mybatis.test;
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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisIntroductionTest {
public static void main(String[] args) throws IOException {
//1.获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//2.获取SqlSessionFactory对象,通过传入输入流的文件路径在工厂builder.build方法来进行创建
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");//填写mybatis-config.xml文件的路径
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//3.获取SqlSession对象,通过工厂的openSession方法进行获取
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.执行SQL语句
int count = sqlSession.insert("car");//放入设置的mapper文件里sql语句的id
//返回值是影响数控表当中的记录条数
System.out.println("插入了几条记录:" + count);
//5.然后手动提交,因为SqlSession不支持自动提交
sqlSession.commit();
//6.关闭资源,(只关闭是不会提交的)
sqlSession.close();
}
}
注意1:默认采用的事务管理器是:JDBC。JDBC事务默认是不提交的,需要手动提交
mybatis中sql语句的结尾;
可以省略
Resources.getResourceAsStream小技巧:
以后繁琐遇到resource这个单词,大部分情况下,这种加载资源的方式就是从类的根路径下开始加载的。
InputStream is = new FileInputStream("d ::\\mybatis-config.xml");
采用这种方式获取也可以
所以:
- mybatis核心配置文件的名字,不一定是:mybatis-config.xml。可以是其他的名字
- mybatis核心配置文件存放的路径,也不一定是再类的根路径下。可以放到其他位置。但是为了项目的可移植性,最好将这个配置文件放到类路径下
系统类加载器有一个方法叫做:getResourceAsStream
它就是从类路径当中加载资源的。
通过源代码分析发现:
InputStream is = Resources.getResourceAsStream( "mybatis-config.xml");
底层的源代码其实就是:
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
CarMapper.xml文件的名字是固定的吗?
都不是固定的。
resource属性:这种方式是从类路径当中加载资源。
url属性:这种方式是从绝对路径当中加载资源。
在mybatis-config.xml文件中,可以通过以下的配置进行mybatis的事务管理
在mybatis中提供了两种事务管理:
- 第一种:JDBC事务管理
- 第二种:MANAGED事务管理
JDBC事务管理器:
SqlSession sqlSession = sqlSessionFactory.openSession(true);
conn.setAutoCommit(false);
conn.setAutoCommit(false);
那么autoCommit就是trueMANAGED事务管理器:
mybatis不再负责事务的管理了。事务管理交给其他容器来负责。例如:spring—— 我不管事务了,你来负责
对于我们当前的单纯的只有mybatis的情况下,如果配置为:MANAGED
那么事务这块是没人管的。没有人管理事务表示事务压根没有开启
public class MyBatisIntroductionTest {
public static void main(String[] args) throws IOException {
//1.获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//2.获取SqlSessionFactory对象,通过传入输入流的文件路径在工厂builder.build方法来进行创建
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");//填写mybatis-config.xml文件的路径
//Resources.getResourceAsStream默认就是从类的根路径下开始查找资源
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);//一般情况下都是一个数据库对应一个SqlsessionFactory对象
//3.获取SqlSession对象,通过工厂的openSession方法进行获取
// SqlSession sqlSession = sqlSessionFactory.openSession(); //如果使用的事务管理器是JDBC的话,底层实际上会执行: conn.setAutoCommit(false);
//这种方式实际上是不建议的,因为么一开启事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.执行SQL语句
int count = sqlSession.insert("car");//放入设置的mapper文件里sql语句的id
//返回值是影响数控表当中的记录条数
System.out.println("插入了几条记录:" + count);
//manager时
//5.然后手动提交,因为SqlSession不支持自动提交
// sqlSession.commit(); 如果使用的事务管理器是JDBC的话,底层实际上还是会执行conn.commit();
//6.关闭资源,(只关闭是不会提交的)
sqlSession.close();
}
}
JDBC的事务:
conn.setAutoCommit(false);
的话,默认的autoCommimt是true完整的mybatis程序展示:
package com.powernode.mybatis.test;
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;
public class MyBatisCompleteTestjava {
//完整的写法
public static void main(String[] args) {
SqlSession sqlSession =null;
try {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
//开启会(底层会开启事务)
sqlSession = sqlSessionFactory.openSession();
//执行SQL语句,处理相关业务
int count = sqlSession.insert("car");
//执行到这里,没有发生任何异常,提交事务,终止事务
sqlSession.commit();
} catch (IOException e) {
//最好回滚事务
if(sqlSession != null){
sqlSession.rollback();
}
e.printStackTrace();
} finally {
//关闭会话(释放资源)
if(sqlSession != null){
sqlSession.close();
}
}
}
}
使用JUnit步骤:
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
你要测试的类名+Test
注解进行标注。
// 测试用例
public class CarMapperTest{
// 测试方法
@Test
public void testInsert(){
//单元测试中有两个重要的概念:
//一个是:实际值(被测试的业务方法的真正执行结果)
//一个是:期望值(执行了这个业务方法之后,你期望的执行结果是多少)
}
@Test
public void testUpdate(){}
}
案例:
import com.powernode.junit.service.MathService;
import org.junit.Assert;
import org.junit.Test;
public class MathServiceTest {
@Test
public void testSum(){
//单元测试中有两个重要的概念:
//一个是:实际值(被测试的业务方法的真正执行结果)
//一个是:期望值(执行了这个业务方法之后,你期望的执行结果是多少)
MathService mathService = new MathService();
//获取实际值
int actual = mathService.sum(1, 2);
//期望值
int expected = 3;
//加个断言进行测试
Assert.assertEquals(expected,actual);
}
@Test
public void testSub(){
MathService mathService = new MathService();
int actual = mathService.sub(10, 5);
int expected = 5;
Assert.assertEquals(expected,actual);
}
}
关于mybatis集成日志组件,让我们调试起来更加方便
mybatis常见的集成的日志组件有哪些呢
其中STDOUT_LOGGING是标准日志,mybatis已经实现了这种标准日志。mybatis框架本身已经实现了这种标准只要开启即可。
怎么开启呢?
在
mybatis-config.xml
文件中使用settings标签
进行配置开启。
例如:
- 这个标签在编写的时候需要注意,它应该出现在environments标签之前。注意顺序。当然,不需要记忆这个顺序。因为又dtd文件进行约束,只要参考dta约束即可
- 这种实现也是可以的,可以看到一些信息,比如:连接对象什么时候创建,什么时候关闭,sql语句是怎样的
但是没有详细的日期,线程名字等。如果你想使用更加丰富的配置,可以集成第三方的log组件
标准日志也可以用,但是配置不够灵活,可以集成其他的日志组件,例如:log4j,logback等。
logback是目前日志框架中性能较好的,较流行的,所以我们选它。logback日志框架实现了slf4j标准
引入logback的步骤:
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.11version>
dependency>
<configuration debug="false">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
encoder>
appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.logFileNamePattern>
<MaxHistory>30MaxHistory>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
encoder>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>100MBMaxFileSize>
triggeringPolicy>
appender>
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
root>
configuration>
开启的日志:
创建utils包:
package com.powernode.mybatis.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;
//mybatis工具类
public class SqlSessionUtil {
//工具类的构造方法一般都是私有化的
//工具类中的所有方法都是静态的,直接采用类名即可调用。不需要new对象
// 为了防止new对象,构造方法私有化
private SqlSessionUtil(){}
private static SqlSessionFactory sqlSessionFactory;
//类加载时执行
//SqlSessionUtil工具类在进行第一次加载的时候,
static {
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
// public static SqlSession openSession() throws IOException {
// SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// //SqlSessionFactory对象:一个SqlSessionFactory对于一个environment,一个environment通常是一个数据库环境
// SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
// SqlSession sqlSession = sqlSessionFactory.openSession();
// return sqlSession;
// }
public static SqlSession openSession(){
return sqlSessionFactory.openSession();
}
}
测试:
@Test
public void testInsertCarByUtil(){
SqlSession sqlSession = SqlSessionUtil.openSession();
int count = sqlSession.insert("car");
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
什么是CRUD?
- C:create 增
- R:retrieve 查(检索)
- U:update 改
- D:delete 删
准备工作
mybatis-002-crud
mybatis-config.xml
放在类的根路径下CarMapper.xml
放在类的根路径下logback.xml
放在类的根路径下com.powernode.mybatis.utils.SqlSessionUtil
工具类com.powernode.mybatis.CarMapperTest
使用MAP集合传参
分析以下SQL映射文件中SQL语句存在的问题
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car">
<insert id="insertCar">
insert into t_car(car_num,brand,guide_price,produce_time,car_type) values('103', '奔驰E300L', 50.3, '2022-01-01', '燃油车')
insert>
mapper>
这样写存在的问题是:
- SQL语句中的值不应该是写死到配置文件里,值应该是用户提供的,这样子写在实际开发中不存在。
- 一定是要前端的form表单提交过来数据,然后将值传递给sql语句
之前的JDBC代码是这样写的:
// JDBC中采用 ? 作为占位符。那么MyBatis中会使用什么作为占位符呢?
String sql = "insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(?,?,?,?,?)";
// ......
// 给 ? 传值。那么MyBatis中应该怎么传值呢?
//例如:
ps.setString(1,"103");
ps.setString(2,"奔驰E300L");
ps.setDouble(3,50.3);
ps.setString(4,"2022-01-01");
ps.setString(5,"燃油车");
在MyBatis中可以这样做:
#{map集合的key}
来完成传值,#{ }
等同于JDBC中的 ?
,#{}
就是占位符范例:
CarMapper.xml:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car">
<insert id="insertCar">
insert into t_car
(id,car_num,brand,guide_price,produce_time,car_type)
values
(null,#{k1},#{k2},#{k3},#{k4},#{k5})#放入map集合的key
insert>
mapper>
测试代码:
package com.powernode.mybatis.test;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
public class CarMapperTest {
@Test
public void testInsertCar(){
SqlSession sqlSession = SqlSessionUtil.openSession();
//假装前端传过来数据了
//这个对象我们先使用Map集合进行数据的封装
HashMap<String, Object> map = new HashMap<>();
map.put("k1","1111");
map.put("k2","byd");
map.put("k3",10.0);
map.put("k4","2020-11-11");
map.put("k5","电车");
//执行sql语句
//insert方法的参数
//第一个参数:sqlid,从CarMapper.xml文件中复制
//第二个参数:封装数据对象
int count = sqlSession.insert("insertCar", map);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
}
所以java程序中使用Map可以给sql语句的占位符传值:
HashMap<String, Object> map = new HashMap<>();
map.put("k1","1111");
map.put("k2","byd");
map.put("k3",10.0);
map.put("k4","2020-11-11");
map.put("k5","电车");
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{k1},#{k2},#{k3},#{k4},#{k5})
注意:#{这里写什么?写map集合的key,如果key不存在,获取的是null}
因此,一般map集合的key起名的时候要见名知意
如下:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car">
<insert id="insertCar">
insert into t_car
(id,car_num,brand,guide_price,produce_time,car_type)
values
(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})#放入map集合的key
insert>
mapper>
package com.powernode.mybatis.test;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
public class CarMapperTest {
@Test
public void testInsertCar(){
SqlSession sqlSession = SqlSessionUtil.openSession();
//假装前端传过来数据了
//这个对象我们先使用Map集合进行数据的封装
HashMap<String, Object> map = new HashMap<>();
map.put("carNum","1111");
map.put("brand","byd");
map.put("guidePrice",10.0);
map.put("produceTime","2020-11-11");
map.put("carType","电车");
//执行sql语句
//insert方法的参数
//第一个参数:sqlid,从CarMapper.xml文件中复制
//第二个参数:封装数据对象
int count = sqlSession.insert("insertCar", map);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
}
java程序中使用POJO类给SQL语句的占位符传值
package com.powernode.mybatis.pojo;
//封装汽车相关信息的pojo类,普遍的java类
public class Car {
// 数据库表当中的字段应该和pojo类的属性一一对应
//建议使用包装类Long,这样可以防止null的问题
private Long id;
private String carNum;
private String brand;
private Double guidePrice;
private String produceTime;
private String carType;
@Override
public String toString() {
return "Car{" +
"id=" + id +
", carNum='" + carNum + '\'' +
", brand='" + brand + '\'' +
", guidePrice=" + guidePrice +
", produceTime='" + produceTime + '\'' +
", carType='" + carType + '\'' +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCarNum() {
return carNum;
}
public void setCarNum(String carNum) {
this.carNum = carNum;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Double getGuidePrice() {
return guidePrice;
}
public void setGuidePrice(Double guidePrice) {
this.guidePrice = guidePrice;
}
public String getProduceTime() {
return produceTime;
}
public void setProduceTime(String produceTime) {
this.produceTime = produceTime;
}
public String getCarType() {
return carType;
}
public void setCarType(String carType) {
this.carType = carType;
}
public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
this.id = id;
this.carNum = carNum;
this.brand = brand;
this.guidePrice = guidePrice;
this.produceTime = produceTime;
this.carType = carType;
}
public Car(){
}
}
@Test
public void testInsertCarByPOJO(){
SqlSession sqlSession = SqlSessionUtil.openSession();
//封装数据
Car car = new Car(null,"3333","bydnmd",30.0,"2020-11-11","新能源");
int count = sqlSession.insert("insertCar", car);//第一个放入的是CarMapper.xm里面的sqlid
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
#{ }
里写的是POJO的属性名
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="car">
<insert id="insertCar">
insert into t_car(id,car_num,brand,guide_price,produce_time,car_type)
values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
insert>
mapper>
经过测试得出结论:
严格意义上来说:如果使用POJO对象传递值的话,#{}这个大括号中到底写什么?
写的是get方法名去掉get,然后将剩下的单词首字母小写,然后放进去
例如:getUsername() --> #{username}
如果采用map集合传参,#{}
里写的是map集合的key,如果key不存在不会报错,数据库表中会插入NULL
。
如果采用POJO传参,#{}
里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写(例如:getAge对应的是#{age}
,getUserName对应的是#{userName}
,如果这样的get方法不存在会报错。
注意:其实传参数的时候有一个属性parameterType,这个属性用来指定传参的数据类型,不过这个属性是可以省略的
需求:根据id删除数据
注意:当占位符只有一个的时候,
${}
里面的内容可以随便写。
<delete id="deleteById">
delete from t_car where id = #{SuiBianXie}
delete>
@Test
public void testDeleteById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
int count = sqlSession.delete("deleteById", 5);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
需求:根据id修改某条记录
<update id="updateById">
update t_car set
car_num = #{carNum},
brand = #{brand},
guide_price = #{guidePrice},
produce_time = #{produceTime},
car_type = #{carType}
where id = #{id}
update>
@Test
public void testUpdateById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
//4L表示的是Long类型表示id:4 Long类型
Car car = new Car(4L,"9999","magua",30.3,"1999-11-10","旧能源");
int count = sqlSession.update("updateById", car);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
当然,如果使用map传数据也是可以的
select语句和其它语句不同的是:查询会有一个结果集对象:ResultSet。
需求:查询id为1的Car信息
<select id="selectById">
select * from t_car where id = #{id}
select>
@Test
public void testSelectById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
//执行sql语句
Object car = sqlSession.selectOne("selectById", 1);
System.out.println(car);
sqlSession.commit();
sqlSession.close();
}
紧接着就报错了:
表示:已运行查询,但未找到映射语句" "的结果映射。很有可能既没有指定结果类型也没有指定结果映射
- 运行后之前的异常不再出现了,这说明添加了resultType属性之后,解决了之前的异常,可以看出resultType是不能省略的:
- 需要特别注意的是:select标签中resultType属性,这个属性用来告诉mybatis,查询结果集封装成说明类型的java对象。你需要告诉mybatis。reultType通常写的是:全限定类名
<select id="selectById" resultType="com.powernode.mybatis.pojo.Car">
select * from t_car where id = #{id}
select>
通过观察发现:只有id和brand是一致的,其他字段名和属性名对应不上,这是不是导致null的原因呢?
- carNum以及其他的这几个属性没有赋上值的原因是:
- car_num、guide_price、produce_time、car_type这是查询结果的列名。
这些列名和Car类中的属性名对不上。- car类的属性名:
carNum、guidePrice、produceTime、carType
那么这个问题该怎么解决?
我们尝试在sql语句中使用as关键字来给查询结果列名起别名试试:
<select id="selectById" resultType="com.powernode.mybatis.pojo.Car">
select
id,car_num as carNum,brand,guide_price as guidePrice,
produce_time as procedureTime,
car_type as carType
from t_car
where id = #{id}
select>
通过测试得知,如果当查询结果的字段名和java类的属性名对应不上的话,可以采用as关键字起别名,当然还有其它解决方案,我们后面再看。
需求:查询所有的Car信息
<select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">
select
id,car_num as carNum,brand,guide_price as guidePrice,
produce_time as procedureTime,
car_type as carType
from t_car
select>
@Test
public void testSelectAll(){
SqlSession sqlSession = SqlSessionUtil.openSession();
List<Object> cars = sqlSession.selectList("selectAll");
cars.forEach(car -> System.out.println(car));
sqlSession.commit();
sqlSession.close();
}
注意:resultType还是指定要封装的结果集的类型。不是指定List类型,是指定List集合中元素的类型。selectList方法: mybatis通过这个方法就可以得知你需要一个List集合。它会自动给你返回一个List集合
在SQL Mapper配置文件中
标签的namespace属性可以翻译为命名空间,这个命名空间主要是为了防止sqlId冲突的。
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="aaaaaaaaaaaaaaa">
<select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">
select
id,car_num as carNum,brand,guide_price as guidePrice,
produce_time as procedureTime,
car_type as carType
from t_car
select>
mapper>
不难看出,CarMapper.xml和UserMapper.xml文件中都有 id=“selectAll”
将UserMapper.xml配置到mybatis-config.xml文件中
@Test
public void testNamespace(){
// 获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.openSession();
// 执行SQL语句
List<Object> cars = sqlSession.selectList("selectCarAll");
// 输出结果
cars.forEach(car -> System.out.println(car));
}
报错:
【翻译】selectCarAll在Mapped Statements集合中不明确(请尝试使用包含名称空间的全名,或重命名其中一个条目)
【大致意思是】selectCarAll重名了,你要么在selectCarAll前添加一个名称空间,要有你改个其它名字。
@Test
public void testNameSpace(){
SqlSession sqlSession = SqlSessionUtil.openSession();
//List
//正确完整的写法:namespace.id
List<Object> cars = sqlSession.selectList("aaaaaaaaaaaaaaa.selectAll");
cars.forEach(car-> System.out.println(car));
sqlSession.commit();
sqlSession.close();
}