<table><tbody><tr><td>为什么要使用框架?使用软件框架的优点总结</td></tr></tbody></table>
思维导图
导学
MyBatis是一个大名鼎鼎的ORM框架,对于我们进行数据库开发有着非常优秀的支持。 首先我们要了解,什么是框架?框架,即 framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。
【资料图】
打个比方,Java 框架跟建筑中的框架式结构是一样的。使用了框架(钢筋+混凝土)以后,你所专著的只是业务(非承重墙构建不同格局),当然是在遵守框架的协议上开发业务。
为什么要使用框架? 因为软件系统发展到今天已经很复杂了,特别是服务器端软件,涉及到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。而且框架一般是成熟,稳健的,你可以处理系统很多细节问题,比如,事物处理,安全性,数据流控制等问题。还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处。 比如,我们可以自己DIY一台电脑,这就是因为我们可以使用一个现成的主板,在这个主板上有着许多规范的接口可供其他设备加入。软件开发中的框架
框架是可被应用开发者定制的应用骨架框架是一种规则,保证开发者遵守相同的方式开发程序框架提倡“不要重复造轮子”,对基础功能进行封装
使用软件框架的优点总结
极大的提高了开发的效率统一的编码规则,利于团队管理灵活配置的应用,拥有更好的维护性
SSM框架介绍
Spring 对象容器框架,提供底层的对象管理,是框架的框架,其他的框架都要基于该框架进行开发。Spring MVC web开发框架,用于替代servlet,提供Web底层的交互,进行更有效的web开发。Mybatis 数据库框架,用于简化数据库操作,对JDBC进行了封装及扩展,提供了数据库的增删改查的便捷操作
补充介绍:SSH框架其实指的是Spring+Struts2+Hibernate框架,该框架更贴近于我们之前的Java Web学习内容,较为老旧,需要较多的配置文件,并不怎么方便。
补充介绍:常用的数据库框架其实还有MyBatis Plus和iBatis框架等。
MyBatis框架介绍
MyBatis是优秀的持久层框架 --将内存中的数据保存在数据库中MyBatis使用XML将SQL与程序解耦,便于维护MyBatis学习简单,执行高效,是JDBC的延伸
对象的两种状态:
瞬时状态:程序中运行的对象,对象保存在内存中,当程序中断或者结束(计算机关闭或重启),该状态对象不会保留。持久化状态:把对象数据保留在文件中,文件存储在永久的存储介质里(光盘、硬盘),当程序中断或者计算机重启断电,该状态的对象会永久保留。 所谓的持久化就是把瞬时状态的对象转换为持久化状态的对象。
MyBatis开发流程-非xml形式
引入MyBatis依赖创建核心配置文件创建实体(Entity)类创建Mapper映射文件初始化SessionFactory利用SqlSession对象操作数据
ORM框架
O:java Object 即 Java 中的对象; R:relationship 即关系数据库; M:mapping 将JAVA中的对象映射成关系型数据库中的表;
MyBatis 框架是一个可以自定义 SQL 和 OR 映射的持久化框架; 框架抛弃了大部分的 JDBC 代码,也不需要手工设置参数以及结果集的操作; 框架使用简单的 XML 配置或者注解来映射数据类型和关系,相对于 Hibernate 框架,MyBatis 是一种半自动化的 ORM 实现。
MyBatis配置
在本课程中,MyBatis将依赖于Maven进行管理。 在MyBatis中,使用xml进行配置,有一个约定俗成的文件名叫做mybatis-config.xml,它是mybatis的一个核心配置文件。
1. Mybatis采用xml文件配置数据库环境信息2. Mybatis环境配置标签3. environment配置包含数据库驱动,URL,用户名和密码
前期准备-新建项目pom.xml
4.0.0<groupId>com.dodoke</groupId><artifactId>mybatis</artifactId><version>1.0.0-SNAPSHOT</version><repositories> <repository> <id>aliyun</id> <name>aliyun</name> <!-- 可能阿里云仓库的地址会发生变化,需要查找最新的地址 --> <url>https://maven.aliyun.com/repository/public</url> </repository></repositories><dependencies> <!-- 数据库驱动依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.18</version> </dependency> <!-- mybatis依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency></dependencies>
前期准备-数据库设计下载地址https://pan.baidu.com/s/1xgxXH9tPn0O_Qf5QfmmbBg 提取码 mso3设置idea连接数据库resources目录下设置mybatis的核心配置文件mybatis-config.xml
SqlSessionFactory & SqlSession
SqlSessionFactory是MyBatis中的一个重要的对象,它是用来创建SqlSession对象的,而SqlSession用来操作数据库的。介绍:
SqlSessionFactory是MyBatis的核心对象SqlSessionFactory用于初始化MyBatis,读取配置文件。是一个工厂方法,用于创建SqlSession对象。要保证SqlSessionFactory在应用全局中只存在唯一的对象,通常会使用静态类的方式对其进行初始化。
SqlSession是MyBatis用来操作数据库的一个核心对象,不那么严谨的说,可以将SqlSession看做类似于我们之前学习过的JDBC的连接接口对象(Connection)执行接口对象(PreparedStatement)的组合,用来执行CRUD操作。介绍:
SqlSession是MyBatis操作数据库的核心对象SqlSession使用JDBC的方式与数据库交互SqlSession对象提供了数据表的CRUD方法
示例引入Junit组件进行测试应用 依赖:
junitjunit4.12
测试代码:
package com.dodoke.mybatistest;
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 java.io.IOException; import java.io.Reader; import java.sql.Connection;
/**
Junit单元测试用例类
规范存放在maven项目的test文件夹中 */ public class MyBatisTest {
@Test public void sqlSessionFactoryTest() throws IOException {//通过MyBatis提供的资源类,获取对应的配置文件作为字符流读取 //getResourceAsReader方法会默认的从当前classpath类路径下加载文件 Reader reader = Resources.getResourceAsReader(“mybatis-config.xml”); //初始化SqlSessionFactory,并同时解析mybatis-config.xml文件 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); System.out.println(“SqlSessionFactory对象加载成功”); //创建SqlSession对象,用于与数据库产生交互,注意SqlSession它是JDBC的扩展类 SqlSession sqlSession = null; try {sqlSession = sqlSessionFactory.openSession(); //在SqlSession对象底层存在Connection(java.sql)连接对象,可以通过getConnection方法得到该对象 Connection connection = sqlSession.getConnection(); //该connection对象的创建仅做演示测试用,在mybatis中,无需使用任何与JDBC有关的类 System.out.println(connection); } catch (Exception e) {e.printStackTrace(); } finally {if(sqlSession != null) {//在mybatis-config.xml文件中,dataSource节点type属性: //如果type=“POOLED”,代表使用连接池,close则是将连接回收到连接池中 //如果type=“UNPOOLED”,代表直连,close则会调用Connection.close()方法关闭连接 //这是配置带来的底层处理机制的不同 sqlSession.close(); } } }
}
设置MybatisUtils工具类
在之前的课程中,我们提到需要保证SqlSessionFactory在全局中保证唯一,那么如何保证该SqlSessionFactory在应用全局保证唯一呢? 通过额外创建的工具类MybatisUtils对SqlSessionFactory对象的初始化以及SqlSession对象的创建和释放方法进行封装 。说明:
一般工具类放在utils包下;用static代码块对静态对象进行初始化;这边我们在异常捕获后将类的初始化的过程中产生的异常抛出,为了外界能捕获到这个异常信息并进行后续处理,而不是直接终止运行程序,我们需要将异常抛出;提供SqlSession对象的创建与释放方法,工具类的大多数方法要使用static进行描述。
工具类代码
package com.dodoke.mybatis;
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.Reader;
/**
MyBatisUtils工具类,创建全局唯一的SqlSessionFactory对象 */ public class MyBatisUtils {//设置私有静态属性,因为静态内容属于类而不属于对象,且拥有全局唯一的特性 private static SqlSessionFactory sqlSessionFactory = null;
//利用静态代码块在初始化类时实例化sqlSessionFactory属性 static {try {Reader reader = Resources.getResourceAsReader(“mybatis-config.xml”); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (IOException e) {e.printStackTrace(); //需要抛出初始化的异常,并且传入捕捉到的异常,形成一条完整的异常链 //以便于通知调用者 throw new ExceptionInInitializerError(e); } }
/**
获取数据库交互SqlSession@return SqlSession对象 */ public static SqlSession openSqlSession() {return sqlSessionFactory.openSession(); }
/**
释放一个有效的SqlSession对象@param sqlSession 准备释放的SqlSession对象 */ public static void closeSqlSession(SqlSession sqlSession) {if(sqlSession != null) {sqlSession.close(); } } }
测试类单元测试代码
/** * MyBatisUtils使用指南 * @throws Exception */@Testpublic void testMyBatisUtils() throws Exception { SqlSession sqlSession = null; try { sqlSession = MyBatisUtils.openSqlSession(); Connection connection = sqlSession.getConnection(); System.out.println(connection); }catch (Exception e){ throw e; } finally { MyBatisUtils.closeSqlSession(sqlSession); }}
MyBatis数据查询
在MyBatis中,虽然我们可以使用MyBatis之前的旧形式,写出如同JDBC那样Java代码和SQL代码混合的数据操作命令,但是我们不建议大家这么做! 对于MyBatis数据查询,可以总结出如下的步骤:1. 创建实体类(Entity)在main/java下创建com.dodoke.mybatis.entity包,entity包下创建数据库中t_goods表对应的Goods商品实体类,将数据表中的字段对应在实体类中增加一系列的私有属性及getter/setter方法,属性采用驼峰命名。
/** * 数据库t_goods表对应映射的实体类 */public class Goods { private Integer goodsId;//商品编号 private String title;//标题 private String subTitle;//子标题 private Float originalCost;//原始价格 private Float currentPrice;//当前价格 private Float discount;//折扣率 private Integer isFreeDelivery;//是否包邮 ,1-包邮 0-不包邮 private Integer categoryId;//分类编号public Integer getGoodsId() { return goodsId;}public void setGoodsId(Integer goodsId) { this.goodsId = goodsId;}public String getTitle() { return title;}public void setTitle(String title) { this.title = title;}public String getSubTitle() { return subTitle;}public void setSubTitle(String subTitle) { this.subTitle = subTitle;}public Float getOriginalCost() { return originalCost;}public void setOriginalCost(Float originalCost) { this.originalCost = originalCost;}public Float getCurrentPrice() { return currentPrice;}public void setCurrentPrice(Float currentPrice) { this.currentPrice = currentPrice;}public Float getDiscount() { return discount;}public void setDiscount(Float discount) { this.discount = discount;}public Integer getIsFreeDelivery() { return isFreeDelivery;}public void setIsFreeDelivery(Integer isFreeDelivery) { this.isFreeDelivery = isFreeDelivery;}public Integer getCategoryId() { return categoryId;}public void setCategoryId(Integer categoryId) { this.categoryId = categoryId;}
}
2. 创建Mapper XML说明SQL语句第二步,第三步结合使用,具体内容在第三步中。3. 在Mapper XML中增加SQL语句对应标签在main/resources下创建新的子目录mappers,mappers代表映射器,里面存放的都是xml文件。创建GoodsMapper.xml文件来说明实体类和数据表的对应关系(和哪个数据表对应,属性和字段怎么对应)。 说明:A.根节点通过增加不同的命名空间namespace来区分不同的mapper文件,通常我们会将针对一张表操作的SQL语句放置在一个mapper文件中。B.语句节点的id属性为别名,相当于SQL名称,同一个namespace下id要唯一,不同的namespace可以重名;因此namespace的设置就很有必要,不然调用SQL的时候分不清哪个idC.语句节点的resultType属性代表返回的对象是什么,为实体类的完整路径,在SQL语句执行完后会自动的将得到的每一条记录包装成对应的实体类的对象;
select * from t_goods order by goods_id desc limit 10
4. 在mybatis-config.xml中增加Mapper XML文件声明其实就是让MyBatis认识新创建的GoodsMapper.xml: 在mybatis-config.xml中添加mappers标签,这样MyBatis在初始化的时候才知道这个GoodsMapper.xml的存在。
5. 利用SqlSession执行Mapper XML中的SQL语句
/** * select查询语句执行 * @throws Exception */@Testpublic void testSelectAll() throws Exception { SqlSession session = null; try{ session = MyBatisUtils.openSqlSession(); //selectList代表查询多条数据,selectOne代表查询一条结果 Listlist = session.selectList("com.dodoke.mybatis.resources.mappers.GoodsMapper.selectAll"); for(Goods g : list){ System.out.println(g.getTitle()); } }catch (Exception e){ throw e; }finally { MyBatisUtils.closeSqlSession(session); }}
对于这样的查询,其实获取到的数据是存在数据丢失的,这是因为我们的查询结果类型字段和表中字段名不能匹配!6. 在mybatis-config.xml中开启驼峰命名映射其实第六步应该放在第五步之前,这里只是给大家作为演示。
goodsId -->
MyBatis的SQL传参
在实现CRUD等操作的时候,有很多的SQL条件数据其实是通过接受前台动态传递过来的参数决定的。那么如何设置这些SQL语句的参数呢? 在数据操作节点中,可以添加parameterType属性指定参数类型,并采用#{param}的形式接受传入的参数。 示例: GoodsMapper.xml
select * from t_goods where goods_id = #{value}
测试:
/** * 传递单个SQL参数 * @throws Exception */@Testpublic void testSelectById() throws Exception { SqlSession session = null; try{ session = MyBatisUtils.openSqlSession(); //传入的参数类型需要和对应数据操作节点中指明的参数类型一致 Goods goods = session.selectOne("com.dodoke.mybatis.resources.mappers.GoodsMapper.selectById" , 1603); System.out.println(goods.getTitle()); }catch (Exception e){ throw e; }finally { MyBatisUtils.closeSqlSession(session); }}
/**
传递多个SQL参数@throws Exception */ @Test public void
testSelectByPriceRange() throws Exception {SqlSession session = null;
try{session = MyBatisUtils.openSqlSession(); Map param = new HashMap();
//map中的key-value的key值,需要和数据操作节点中参数名一致 param.put(“min”,100); param.put(“max” ,
500); param.put(“limt” , 10); List
多表关联查询
在之前的学习中,我们针对的都是一个表的查询,那么如何针对多表进行联合查询呢? 其实我们可以将返回的结果变为Map类型,这样MyBatis就会将结果封装为Map集合中对应的键值对
select g.* , c.category_name from t_goods g , t_category c where g.category_id = c.category_id
/** * 利用Map接收关联查询结果 * @throws Exception */@Testpublic void testSelectGoodsMap() throws Exception { SqlSession session = null; try{ session = MyBatisUtils.openSqlSession(); Listlist = session.selectList("com.dodoke.mybatis.resources.mappers.GoodsMapper.selectGoodsMap"); for(Map map : list){ System.out.println(map); } }catch (Exception e){ throw e; }finally { MyBatisUtils.closeSqlSession(session); }}
我们可以看到,该方法返回的结果为数据库中表对应的原始字段名为key值,而且查询到的结果的顺序是混乱的。 为了保证我们等到的结果的顺序和数据库中的顺序一致,我们需要使用LinkedHashMap。
LinkedHashMap是采用链表形式的HashMap,他在进行数据提取的时候是按照插入数据时的顺序进行提取保存的,不会出现乱序的情况。使用LinkedHashMap来接收数据是常用的,因为公司的数据结构较为复杂,需要多表关联查询,LinkedHashMap可以有效进行数据的扩展,非常灵活。缺点:太过灵活,任何查询结果都会被LinkedHashMap包装在内,相比较实体类而言,缺少了编译时检查,是很容易出错的。
select g.* , c.category_name,"1" as test from t_goods g , t_category c where g.category_id = c.category_id
其实针对于这样的多表查询,我们还可以通过修改实体类来实现,显得不够灵活,但是却可以保证在编译的时候进行检查。具体选用哪种方式可以根据实际情况进行选择。 PS:注意,在之前我们的学习中,我们是利用在mybaits-config.xml文件中设置驼峰映射的方式,来解决字段和实体类属性名称不能匹配的问题的,但是我们也可以设置在查询的时候起别名的方式,解决这个问题。
ResultMap结果映射
介绍:
ResultMap可以将查询结果映射为复杂类型的Java对象。ResultMap适用于Java对象保存多表关联结果ResultMap是MyBatis关联的核心所在,支持对象关联查询等高级特性
在上节课程中,我们也提到过,可以为了查询结果去修改实体类。但是,这种方式在标准的mybatis开发下是不太建议的。实体类仅仅和数据表对应就好,不要添加一些冗余的属性,但是在实际开发中,我们有时为了方便,实际上较多的还是采用修改实体类的形式。 但是,采用DTO,数据扩展类开发的形式,我们同学们必须掌握。 在com.dodoke.mybatis包下面新建一个dto包,新建GoodsDTO类。
DTO是一个特殊的JavaBean,数据传输对象。对原始对象进行扩展,用于数据保存和传递。
/** * 扩展类,数据传输对象 */public class GoodsDTO { private Goods goods = new Goods(); private String categoryName; private String test;public Goods getGoods() { return goods;}public void setGoods(Goods goods) { this.goods = goods;}public String getCategoryName() { return categoryName;}public void setCategoryName(String categoryName) { this.categoryName = categoryName;}public String getTest() { return test;}public void setTest(String test) { this.test = test;}
}
使用resultMap属性,添加结果映射
select g.* , c.*,"1" as test from t_goods g , t_category c where g.category_id = c.category_id
测试
/** * 利用ResultMap进行结果映射 * @throws Exception */@Testpublic void testSelectGoodsDTO() throws Exception { SqlSession session = null; try{ session = MyBatisUtils.openSqlSession(); Listlist = session.selectList("com.dodoke.mybatis.resources.mappers.GoodsMapper.selectGoodsDTO"); for (GoodsDTO g : list) { System.out.println(g.getGoods().getTitle()); } }catch (Exception e){ throw e; }finally { MyBatisUtils.closeSqlSession(session); }}
其实我们可以继续扩展,比如我现在不仅仅想要得到category_name产品名称,还想要获得其他属性,那么我们该怎么办呢? 新建t_category表的实体类
package com.dodoke.mybatis.entity;
public class Category {private Integer categoryId; private String categoryName; private Integer parentId; private Integer categoryLevel; private Integer categoryOrder;
public Integer getCategoryId() { return categoryId;}public void setCategoryId(Integer categoryId) { this.categoryId = categoryId;}public String getCategoryName() { return categoryName;}public void setCategoryName(String categoryName) { this.categoryName = categoryName;}public Integer getParentId() { return parentId;}public void setParentId(Integer parentId) { this.parentId = parentId;}public Integer getCategoryLevel() { return categoryLevel;}public void setCategoryLevel(Integer categoryLevel) { this.categoryLevel = categoryLevel;}public Integer getCategoryOrder() { return categoryOrder;}public void setCategoryOrder(Integer categoryOrder) { this.categoryOrder = categoryOrder;}
}
修改DTO数据对象
package com.dodoke.mybatis.dto;
import com.dodoke.mybatis.entity.Category; import com.dodoke.mybatis.entity.Goods;
/**
扩展类,数据传输对象 */ public class GoodsDTO {private Goods goods = new Goods(); private Category category = new Category(); private String test;
public Goods getGoods() {return goods; }
public void setGoods(Goods goods) {this.goods = goods; }
public Category getCategory() {return category; }
public void setCategory(Category category) {this.category = category; }
public String getTest() {return test; }
public void setTest(String test) {this.test = test; } }
修改映射结果集
select g.* , c.*,"1" as test from t_goods g , t_category c where g.category_id = c.category_id
MyBatis数据写入
在之前的课程中,我们实现了MyBatis的数据查询工作,接下来,我们来看看如何实现数据的新增,修改和删除工作。
数据库事务
提到数据库的写入操作,就离不开数据库的事务。数据库事务是保证数据操作完整性的基础所有从客户端发来的新增修改删除操作,都会被事务日志所记录,我们形象的将事务日志看成流水账,它记录客户端发来的所有写操作的前后顺序, 当客户端向MySQL服务器发起了一个commit提交命令的时候,事务日志才会将这三个数据同时的写入到数据表中,在commit的时候才是真正的往数据表写入的过程,当这三条数据都被成功写入到数据表中后,刚才所产生的事务日志都会被清空掉。 假设如果客户端在处理这些数据的时候,数据1和数据2执行成功,数据3因为各种原因没有执行成功的话,客户端会发起一个rollback回滚命令,当MySQL收到了rollback回滚命令后,当前事务日志中的所有已经产生的数据都会被清除,这就意味着前面已经产生的数据1和数据2不会放入到数据表中,只有当所有数据都完成的时候,在由客户端发起commit提交,数据才能成功的写入。要么数据全部写入成功,要么中间出现了任何问题,全部回滚,保证了数据的完整性
案例
修改MyBatisUtils
/** * 获取数据库交互SqlSession * @return SqlSession对象 */public static SqlSession openSqlSession() { //默认SqlSession对自动提交事务数据(commit) //设置false代表关闭自动提交,改为手动提交事务数据 return sqlSessionFactory.openSession(false);}
新增
INSERT INTO t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery, category_id) VALUES (#{title} , #{subTitle} , #{originalCost}, #{currentPrice}, #{discount}, #{isFreeDelivery}, #{categoryId}) select last_insert_id()
/** * 新增数据 * @throws Exception */@Testpublic void testInsert() throws Exception { SqlSession session = null; try{ session = MyBatisUtils.openSqlSession(); Goods goods = new Goods(); goods.setTitle("测试商品"); goods.setSubTitle("测试子标题"); goods.setOriginalCost(200f); goods.setCurrentPrice(100f); goods.setDiscount(0.5f); goods.setIsFreeDelivery(1); goods.setCategoryId(43); //insert()方法返回值代表本次成功插入的记录总数 int num = session.insert("com.dodoke.mybatis.resources.mappers.GoodsMapper.insert", goods); session.commit();//提交事务数据 System.out.println(goods.getGoodsId()); }catch (Exception e){ if(session != null){ session.rollback();//回滚事务 } throw e; }finally { MyBatisUtils.closeSqlSession(session); }}
我们在上述代码中可以利用selectKey标签获得对应的新增主键,其实我们还可以利用另外一个属性userGenerateKeys实现获得新增主键,它们的区别在哪里呢?
SelectKey适用于所有数据库,但需要根据不同的数据库编写对应的获得最后改变主键值得查询语句userGenerateKeys只支持“自增主键”的数据库(DB2,Oracle等没有自增主键约束),但使用简单,会根据不同的数据库驱动自动编写查询语句,以下是该属性的使用方法
insert 语句
如果要在Oracle中获得新增后的主键,需要借助序列来实现,其实是通过序列在执行新增语句之前生成一个新的序列值并保存到主键字段中。更新与删除
UPDATE t_goods SET title = #{title} , sub_title = #{subTitle} , original_cost = #{originalCost} , current_price = #{currentPrice} , discount = #{discount} , is_free_delivery = #{isFreeDelivery} , category_id = #{categoryId} WHERE goods_id = #{goodsId}
/** * 更新数据 * @throws Exception */@Testpublic void testUpdate() throws Exception { SqlSession session = null; try{ session = MyBatisUtils.openSqlSession(); Goods goods = session.selectOne("com.dodoke.mybatis.resources.mappers.GoodsMapper.selectById", 739); goods.setTitle("更新测试商品"); int num = session.update("com.dodoke.mybatis.resources.mappers.GoodsMapper.update" , goods); session.commit();//提交事务数据 }catch (Exception e){ if(session != null){ session.rollback();//回滚事务 } throw e; }finally { MyBatisUtils.closeSqlSession(session); }}/** * 删除数据 * @throws Exception */@Testpublic void testDelete() throws Exception { SqlSession session = null; try{ session = MyBatisUtils.openSqlSession(); int num = session.delete("com.dodoke.mybatis.resources.mappers.GoodsMapper.delete" , 739); session.commit();//提交事务数据 }catch (Exception e){ if(session != null){ session.rollback();//回滚事务 } throw e; }finally { MyBatisUtils.closeSqlSession(session); }}
预防SQL注入攻击
在之前的学习中,我们了解到什么是SQL注入攻击,并且在JDBC课程中也去实现了如何预防SQL注入攻击。那么,在MyBatis中如何去进行SQL注入攻击的预防呢? 其实,SQL注入攻击的原理非常简单,就在在接收用户输入的时候,不对接收的数据进行任何的判断和转义,导致在接收时可能全盘接收到诸如单引号、or等一些SQL关键字。 所以,预防SQL注入攻击需要的是对接收数据进行判断和转义。在MyBatis中,这些工作其实早就已经为我们准备好了。MyBatis两种传值方式
${}文本替换,未经任何处理对SQL文本替换#{}预编译传值,使用预编译传值可以预防SQL注入
在我们的实际使用中,更多的还是通过#{}的形式进行传值
标签:
相关推荐:
精彩放送:
- []今日观点!世茂股份拟召开债券持有人会议,所有存续公司债12月9日开市起停牌
- []多家房企抛出股权融资方案 地产行业困境反转?
- []消息!又一家大行看多!摩根士丹利:中国股票将跑赢全球
- []金溢科技:关于股东人数情况,详见公司最近一期定期报告
- []格力地产调整重组方案:募集配套资金超8亿元,明日复牌
- []【播资讯】“小步快跑”供地风向标显现 武汉率先开启第六批集中供地
- []世界热点评!45个重点城市城镇化率:这六个城市超90%
- []世界热文:星辉娱乐:(1)近两年,受多种因素影响,公司收入和净利润有所下滑
- []全球速讯:被六省(市)纳入新冠肺炎诊疗方案的化痰止咳中药是怎样炼成的?
- []博雅生物:公司一直在积极推进浆站拓展工作,申请新设浆站存在不确定性,如公司获批新设,将及时披露
- []原油交易提醒:美国料陷入技术性衰退,需求减弱拖累油价五连阴
- []当前资讯!融创发布境外债务初步重组框架:拟将30至40亿美元借款转为普通股等
- []世界快看点丨内蒙一机:公司民品业务涉及铁路车辆及相关零部件,订单任务充足,重要合同签订情况均在临时公告中有披露
- []世界头条:二手房买家因卖家换掉家具拒付尾款遭起诉,法院:出卖人构成违约
- []2022财年亏损18.16亿,靠港府“续命”的香港海洋公园能走多远?
- []每日快看:大叶股份:公司综合考虑质量、性能、交期、价格等多个因素,汽油割草机零部件为全球化采购
- []晋亿实业:公司主要从事各类紧固件的研究和开发,生产销售各类紧固件、铁道扣件等产品,产品远销国内外
- []融创公布境外债重组重大进展 加速回到健康发展轨道
- []新力被债权人放弃了
- []房企融资“三箭齐发”,置业信心能否回暖?
- []【环球速看料】国际油价 7日 显著下跌
- []独立储能电站商业投资价值的识别与分析
- []甘肃多措并举保障冬季电力供应
- []天天快报!电化学储能是什么意思?电化学储能主要包括哪些?
- []焦点!成立1年,业务覆盖30+国家和地区!这家储能公司怎么这么猛?
- []今日看点:车险年底买是否优惠些 年底买车保险会不会优惠些
- []【全球热闻】美股异动 | 中概教育股普涨 新东方(EDU.US)涨超9%
- []【天天新要闻】定向增发+公司债 大名城抛出约50亿元再融资方案
- []保险报案有效期是多久 一般保险报案的有效期限是多长时间
- []保险不续费自动退保吗 保险要是不续费会自行退保吗
- []参保人就是被保险人吗 被保险人是不是参保人
- []公积金一定要留余额吗 公积金必须留余额吗
- []岁宝百货深圳宏发大世界购物广场门店提前终止租赁协议
- []天天滚动:2023年Q1全球计划运力预计达12亿,法国境内短途航班取消将为对手创造机会
- []头条:川润股份:12月7日公司高管李辉减持公司股份合计5.37万股
- []零售云平台多点数智赴港IPO 腾讯IDG是股东
- []【环球热闻】新湖中宝拟引入衢州国资 由控股股东出让不超过10%股权
- []科蓝软件:12月7日公司高管王安京减持公司股份合计14.84万股
- []全球快讯:龙佰集团:12月7日公司高管张海涛增持公司股份合计1600股
- []世界球精选!历时八个月 南京正式实施商品房预售资金监管新政
- []当前信息:北京银行与重点房地产企业签约,提供意向性融资总额2500亿元
- []环球焦点!格力地产重启收购珠海免税 构建三大业务板块
- []美国房地产大起大落后迎来投资机会
- []每日视点!新柴股份:12月7日公司高管周高峰减持公司股份合计2000股
- []北京银行:为万科、中海、招商等重点房企提供意向性融资总额2500亿元
- []快资讯丨佳力奇:加大自主创新力度 持续巩固技术堡垒
- []当前播报:群兴玩具:截止目前,公司未存在筹划重大资产重组等事项
- []现货黄金持稳,市场权衡两大前景,警惕通胀“挂自动挡”
- []环球今日报丨中指院: A股ESG报告披露率较低
- []人福医药:12月7日徐华斌减持公司股份合计13万股
- []每日快讯!越秀地产前11月合同销售1029.4亿元 完成年度销售目标83%
- []交建股份:11月28日至12月1日公司高管胡先宽、储根法、曹振明、陈明洋、施秀莹减持公司股份合计72.02万股
- []物业流拍、招租进行中,天桥百货觅新生
- []当前关注:合生创展前11月总合约销售额281.13亿元 同比下降27.73%
- []全球观热点:中指院:二十城物业服务收费稳中略升
- []新化股份:12月6日至12月7日公司高管方军伟减持公司股份合计8000股
- []宝龙地产前11月合约销售总额约379.3亿元
- []【天天新要闻】万通发展拟投资5亿元设立通信业务全资子公司
- []全球速读:沃森生物:公司近年来持续从销售体系建设、消费者教育、终端服务和渠道布局多维度打造产品品牌和市场影响力
- []大名城拟定增不超过30亿元 主要投向上海5个项目
- []天天热文:黄山胶囊:我公司根据相关法律、法规及规范性文件的规定标准进行信息披露
- []黄山胶囊:我公司与熊去氧胆酸胶囊暂无合作
- []【新要闻】中南建设三只债券获持有人会议通过 豁免美元债交叉违约
- []每日快报!大名城拟发行本金不超过20亿元的公司债券
- []全球即时看!落子布局电池租赁!宁德时代或许将用换电服务深度绑定车企
- []越秀地产:前11月合同销售额约为人民币1029.4亿元
- []环球快看:中华企业拟非公开发行股票不超过总股本30% 用于“保交楼“项目
- []德艺文创:截至2022年11月30日(目前最新数据)的股东人数为12,383
- []全球热门:中骏集团提前汇出12.87亿以兑付购房尾款ABS本息 年内公开债务“零违约”
- []环球报道:杭州规定保租房租金应低于同类房源市场价格 2023年1月5日起施行
- []全球动态:奥马电器:公司产品为冰箱冷柜,冰箱冷柜为居民生活必备的耐用消费品
- []全球速看:合肥搭建线上服务平台 开启“二手房互换”新模式
- []每日资讯:金石亚药:目前公司产能及备货充足,能够满足市场需求
- []实至名归,箭牌家居荣获行业唯一“2022国际CMF设计奖”金奖!
- []快资讯:虽迟但到 | 2022 环球旅讯峰会,12月底上海见
- []天天速递!图解贵金属及外汇:多空成本+最单边押注(2022/12/08周四)
- []热资讯!中骏安全度过行业低谷期,年内偿还境内外公开债务超70亿元
- []世界热门:豪森股份:公司2022年度向特定对象发行A股股票的定价基准日为发行期首日
- []财面儿丨中骏集团控股1-11月实现累计合同销售金额约544.42亿元
- []天天新动态:西安饮食:该公司并未实际开展业务
- []青岛中程:公司印尼工业园现场员工,克服多方困难,全力推进RKEF镍电项目剩余工程的建设,争取早日交付
- []天天日报丨财面儿|德信中国前11月累计合约销售金额336亿元
- []全球看热讯:物业丨卓越商企服务:全资附属公司收到仲裁通知书
- []【新要闻】比特币概念股票有哪些?2021年比特币概念股一览?
- []快消息!核电股票有哪些?2018核电概念股龙头有哪些?
- []当前快讯:股市熔断机制是什么意思?股市熔断机制有什么意义?
- []今日要闻!物业丨华润万象生活:与华润置地订立商业运营服务框架协议之补充协议
- []全球热议:钼板概念股是哪些?钼板股票一览?
- []资讯推荐:合力泰:公司目前未涉及该业务
- []全球热推荐:甲醇概念上市公司有哪些?甲醇概念股一览?
- []全球短讯!2020年股市休市放假怎么安排的?A股全年休市一览?
- []2020新能源电池概念股票有哪些?2020新能源电池概念股票一览?
- []全球实时:哪些是智能家居概念股?智能家居概念股名单一览?
- []全球消息!抄底是什么意思?抄底的四大形态是怎样的?
- []【热闻】磷化工股票有哪些?相关磷化工概念股票有哪些?
- []【世界新要闻】面板概念龙头股有哪些?2021年面板概念股有哪些?
- []碳中和是什么概念?碳中和概念股有哪些?
- []每日消息!太阳能电池背板上市公司有哪些?太阳能电池背板概念股一览
- []全球滚动:虚拟现实板块股票有哪些?虚拟现实概念股票一览?
- []全球动态:橡胶股票龙头股有哪些?橡胶股票有哪些?
- B站注册资本增幅400%至5亿 目前由陈睿全资持股
- 光源资本出任独家财务顾问 沐曦集成电路10亿元A轮融资宣告完成
- 巨轮智能2021年上半年营收11.24亿元 期内研发费用投入增长19.05%
- 红枣期货尾盘拉升大涨近6% 目前红枣市场总库存约30万吨
- 嘉银金科发布2021年Q2财报 期内净利润达1.27亿元同比增长208%
- 成都银行2021上半年净利33.89亿元 期内实现营收同比增长17.27亿元
- 汽车之家发布2021年第二季度业绩 期内新能源汽车品牌收入增长238%
- 中信银行上半年实现净利润290.31亿元 期末不良贷款余额706.82亿元
- 光伏概念掀起涨停潮交易价格创新高 全天成交额达1.29亿元
- 上半年生物药大增45% 关键财务指标好转营收账款持续下降
- 世界快看:俄油上限刚出台冲击就已显现?俄罗斯原油出口出现急剧减少
- 电缆上市公司有哪些?相关上市公司龙头有哪些?
- 世界快看:核电板块龙头股票有哪些?核电概念股票有哪些?
- 世界微资讯!食用油板块龙头股票有哪些?食用油板块龙头股票有哪些?
- 环球视讯!2021年腾讯概念股票有哪些?腾讯概念股一览?
- 森马服饰股票属于什么板块?森马服饰股票属于哪些概念股?
- MINE's TALK对话祝羽捷,「一个自己的房间」 传递自洽生活哲学
- 世界今头条!国际油价多头须尽快离场,该指标暗示需求担忧仍唱主角
- 中交路桥建设20亿元绿色公司债券已提交注册
- 世界热推荐:中建信息10亿元应收账款资产支持ABS已获受理
- 产业物流线上季快讯 | 王少华:险资在物流上的投资机会将增多
- 绿城房地产拟发行90亿元中票 项目状态为“预评中”
- 上海地铁全线受理云闪付乘车码“一码通行”功能
- 焦点快播:粤万年青:公司产品消炎利胆片功能主治为“清热,祛湿,利胆
- 精彩看点:味知香:公司新产能预计前期先进行部分投产,后期根据生产运营情况,逐步释放产能
- 香港发展局:一般项目由“生地”变成可建屋“熟地”的时间减至4年
- 环球百事通!锡装股份:公司没有上述高送转的计划。感谢您的关心支持!
- 焦点短讯!金价有望继续走强!世界黄金协会称全球央行继续购金,三季度购买量猛增至400吨
- 加码欧洲储能市场 优能新能源发布新一代储能逆变器
- 今热点:Expedia:国际旅行和商旅有望在2023年恢复元气
- 世界热点!美原油交易策略:经济衰退担忧笼罩市场,油价跌势难改
- 头条焦点:国际金价持稳,市场担心美联储继续维持强硬鹰派立场
- 当前速看:现货黄金交易策略:初请数据来袭,关注200日均线阻力
- 携程发布“2023旅游振兴A计划”,三“重”战略促万亿消费
- 天天即时看!冬季冰雪游升温,同程旅行冰雪搜索热度增长150%
- 全球要闻:国际金价或回踩1772美元
- 环球即时:ThinkBook16p对比联想小新 Pro16 2021款哪个值得更好?详细评测
- 焦点热文:北京楼市,变了
- 场景化营销精准发力 钱小乐持续优化金融服务质效
- 环球热头条丨Excel函数之VLOOKUP()怎么使用?一文搞懂Excel函数之VLOOKUP()使用
- “新十条”发布后,这个省份开始抢游客了
- 全球最新:魏小安:旅游业大局三个月可定,六个月可起
- 环球百事通!FFT是什么意思?FFT的详解
- 天天微头条丨disable怎么运用?disable简单易理解用法
- 环球快报:格式化时间是什么?抽象类DateFormat是什么?
- 焦点!中骏集团:前11月合同销售额约544.42亿元
- 全球即时:order by是什么意思?order by的详解
- 天天热消息:java.lang.NullPointerException解决方案是什么?
- 焦点消息!诛仙3新手卡怎么领取?诛仙3新手卡领取中心
- 弘阳地产前11月合约销售额同比减少56.98% 单月同比跌64.3%
- 天天要闻:主板测试卡代码a2是什么?主板测试卡代码 常见代码总结
- UML建模怎么用?UML建模之用例图
- 环球百事通!国产搞笑电视剧排行榜你看过几个?爱情公寓只能排倒数第三
- 【世界快播报】工厂模式是什么?工厂模式的详解
- 世界通讯!黄淮学院最低录取分数线是多少?2022文理科最低分及位次
- 最美夕阳红 携手度余生——富德生命人寿十堰中支用镜头为老人定格相濡以沫的爱情
- 速讯:使用Icon图标的几种方式是啥?Icon图标怎么使用?
- 速看:歌名最长的网络歌曲是什么?歌名最长的中文歌
- fm2015是什么?fm2010战术
- 【独家】.NET Core是什么?NET Core有哪些用处?
- Trans系列是啥?基于翻译模型(Trans系列)的知识表示学习
- 尼康d800与d810哪个好?尼康d800与d810有哪些区别?
- 快看点丨Internal问题解决流程 Internal server error 500 问题解决思路
- 【环球播资讯】12月8日天元股份涨停分析:可降解塑料,包装印刷概念热股
- 每日快播:12月8日焦点科技涨停分析:跨境电商,职业教育,教育概念热股
- 12月8日千红制药涨停分析:肝素,化学原料药,抗原自测概念热股
- 微速讯:转动惯量是什么意思?转动惯量的含义
- 当前焦点!歉疚的意思是什么?歉疚一词详情介绍
- 西米是什么米?西米露和西米是一样的吗?
- 兴民智通:公司目前不触及 st 相关条款
- 世界顶级昂贵音响有哪些?世界顶级昂贵音响介绍
- 世界今日报丨如何正确使用系统清理bat程序?清理bat程序的方法技巧
- 天天微动态丨11月百城二手住宅市场均价稳中趋降
- 【世界热闻】12月8日国光连锁涨停分析:新零售概念热股
- 头条焦点:文章目录是什么?选择排序怎么设置?
- 世界微资讯!网络的利与弊是什么?网络的利弊分析
- 天天快资讯丨吸血鬼狂刀技能搭配详情 吸血鬼狂刀攻略)
- 世界动态:磁条读写器多少钱?磁条读写器使用方法介绍
- Modbus通信协议是什么?Modbus通信协议详解
- JSONObject是什么意思?JSONObject的详情介绍
- 世界关注:iPad Air(iPad5)什么时候上市?iPad Air(iPad5)的上市时间
- 安徽大专学校推荐!安徽大专院校排名前十详细介绍含分数线
- 每日热闻!BOW是什么意思?为什么要用BOW模型描述图像?
- 环球快资讯:铅球世界纪录2019 女子男子铅球世界纪录分别是多少?
- 热门看点:分析宾得645d怎么样?宾得公司详情介绍
- 观察:梯度(gradient)是什么?梯度的概念是建立在哪方面?
- 焦点播报:程子土包子来的时候歌厅的dj叫什么名字?海燕KTV
- 世界视讯!信号的基本概念是什么?信号的分类有哪些?
- 环球实时:电脑电源额定功率要多少才合适?电脑电源的额定功率
- 全球快消息!4399生死狙击万人号账号2021 4399生死狙击好号和密码免费永久2021
- 焦点讯息:OneNote是什么?OneNote的功能有哪些?
- 世界今头条!多普达手机都有哪些型号?多普达最新手机大全详情
- 挥着翅膀的女孩英文版叫什么?挥着翅膀的女孩英语版歌词翻译
- lol怎么在游戏里回复好友?lol游戏回复技巧
- 今日精选:碧海青天的意思是什么?碧海青天一词出自哪里?
- 世界信息:图片或手写签名转电子签名怎么转?手写签名转电子签名教程
- 世界要闻:44岁贾静雯出席活动耳朵被烫伤 修杰楷很是心疼
- 当前视点!手机QQ接收电脑端好友发送的文件存储在什么地方?手机文件储存路径
- 天天速读:语义分割:基于openCV和深度学习(二)
- 支付宝网上银行如何付款?网上银行付款操作流程
- 天天微头条丨用VC6.0实现上位机串口通信
- 全球速看:宝宝毛衣怎么编织?宝宝毛衣编织图解
- 魂锁典狱长二技能怎么用?lol魂锁典狱长背景以及皮肤介绍
- 基础版本的基础版本 直方图均衡化系列
- 天天观速讯丨用身份证办的移动手机号码可以跨省改归属地吗?是不可以的
- 摄像头远程监控步骤是什么?手机远程监控摄像头设置方法
- Android中LayoutParams是什么?Android中LayoutParams总结和用法
- 歌词里有我真的很不错是什么儿歌?歌词我真的很不错是什么儿歌?
- 全球新资讯:会议panel是什么意思?医学术语中的panel到底是指什么?
- 当前动态:颜料墨水和染料墨水的区别是什么?颜料墨水和染料墨水简介