它是我们软件开发中的一套解决方案,不同的框架解决的是不同的问题。
使用框架的好处:
框架封装了很多的细节,使开发者可以使用极简的方式实现功能。大大提高开发效率。
JDBC技术:
Connection
PreparedStatement
ResultSet
Spring的JdbcTemplate:
Spring中对jdbc的简单封装
Apache的DBUtils:
它和Spring的JdbcTemplate很像,也是对Jdbc的简单封装
以上这些都不是框架
JDBC是规范
Spring的JdbcTemplate和Apache的DBUtils都只是工具类
mybatis是一个持久层框架,用java编写的。
它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程它使用了ORM思想实现了结果集的封装。
ORM:
Object Relational Mappging 对象关系映射
简单的说:
就是把数据库表和实体类及实体类的属性对应起来
让我们可以操作实体类就实现操作数据库表。
user User
id userId
user_name userName
我们需要做到
实体类中的属性和数据库表的字段名称保持一致。
user User
id id
user_name user_name
`
创建测试数据库;
第一步:创建maven工程并导入坐标
第二步:创建实体类和dao的接口
第三步:创建Mybatis的主配置文件
SqlMapConifg.xml
导入log4j的配置文件
第四步:创建映射配置文件
IUserDao.xml
第五步:编写测试类
第一个:创建IUserDao.xml 和 IUserDao.java时名称是为了和我们之前的知识保持一致。
在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper
所以:IUserDao 和 IUserMapper是一样的
第二个:在idea中创建目录的时候,它和包是不一样的
包在创建时:com.itheima.dao它是三级结构
目录在创建时:com.itheima.dao是一级目录
第三个:mybatis的映射配置文件位置必须和dao接口的包结构相同
第四个:映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
第五个:映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名
当我们遵从了第三,四,五点之后,我们在开发中就无须再写dao的实现类。
第一步:读取配置文件
第二步:创建SqlSessionFactory工厂
第三步:创建SqlSession
第四步:创建Dao接口的代理对象
第五步:执行dao中的方法
第六步:释放资源
注意事项:
不要忘记在映射配置中告知mybatis要封装到哪个实体类中
配置的方式:指定实体类的全限定类名
pom.xml
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.5version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.32version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
User
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
UserDao
public interface UserDao {
List<User> findAll();
}
mybatis-config.xml
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/atguigu/dao/UserDao.xml"/>
mappers>
configuration>
userDao.xml
<mapper namespace="com.atguigu.dao.UserDao">
<select id="findAll" resultType="com.atguigu.domain.User">
select * from user;
select>
mapper>
测试类
public class Test1 {
@Test
public void test1()throws Exception{
//1.加载配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.创造构建者对象
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
//3.构建者构件工厂
SqlSessionFactory factory = builder.build(is);
//4.使用工厂生产sqlSession
SqlSession session = factory.openSession();
//5.使用sqlSession创建userDao的代理对象
UserDao dao = session.getMapper(UserDao.class);
List<User> users = dao.findAll();
for (User user:users){
System.out.println(user);
}
//6.资源关闭
session.close();
is.close();
}
}
mybatis基于注解的入门案例:
把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL语句
同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。
Dao层
@select("select * from user")
public interface UserDao {
List<User> findAll();
}
mybatis-config.xml
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com.atguigu.dao.UserDao"/>
mappers>
configuration>
明确:
我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式。
不管使用XML还是注解配置。
但是Mybatis它是支持写dao实现类的。
UserDaoImpl
/**
* @author Guohai
* @createTime 2020-07-14 20:40
*/
public class UserDaoImpl implements UserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
public List<User> findAll() {
SqlSession session = factory.openSession();
List<User> list = session.selectList("com.atguigu.dao.impl.UserDaoImpl");
session.close();
return list;
}
}
测试类
public void test1()throws Exception{
//1.加载配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.创造构建者对象
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
//3.构建者构件工厂
/**
* 创建工厂,Mybatis使用了构建者模式,
* 把对象的创建细节隐藏,使使用者直接调用方法
* 就可以拿到对象。
*/
SqlSessionFactory factory = builder.build(is);
//4.使用工厂生产sqlSession
/**
* 使用工厂模式生产SQLSession对象,
* 优势:解耦,降低了类之间的依赖关系
*/
SqlSession session = factory.openSession();
//5.使用sqlSession创建userDao的代理对象
/**
* 创建dao接口实现类使用了代理模式,
* 在不改变源码的基础上对方法进行增强。
*/
UserDao dao = session.getMapper(UserDao.class);
List<User> users = dao.findAll();
for (User user:users){
System.out.println(user);
}
//6.资源关闭
session.close();
is.close();
}
读取配置文件,用到的就是解析xml的技术,
此处用到dom4j解析xml技术。
mybatis-config.xml
1.提供数据源(提供连接对象)
2.指定映射配置信息(指定xxxDao.xml)
xxxDao.xml
1.查询语句
2.封装结果集对象的全限定类名
namespace:xxxDao
-将查询语句和封装结果集对象的全限定类名
封装在一个map集合中,方便查询,
key为dao接口名.方法名,
value为:查询语句和封装结果集对象的全限定类名。
public static void main(String[] args) {
UserDao userDao;
/**
* @param 1.被代理类的类加载器
* @param 2.被代理类实现的接口
* @param 3.对方法的增强:listAll()就是在此处被调用的。
*/
UserDao daoimpl = (UserDao) Proxy.newProxyInstance(
UserDao.class.getClassLoader(),
UserDao.class.getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;//在此处调用查询所有的方法
}
});
}
构建一个属于自己的持久层框架,将会涉及到的一些知识点:工厂模式
(Factory 工厂模式、构造者模式(Builder 模式、代理模式,反射,自定义注解,注解的反射,xml 解析,
数据库元数据,元数据的反射等)
1.用一个流来加载配置文件
解析xml文件
2.用一个类来创建工厂类
构建者模式,隐藏创建细节
3.用工厂类来造sqlSession对象
工厂模式造对象,解耦
4.使用SQLSession动态代理创建dao的接口实现类对象
不改变源码的基础上,对原有方法进行增强。
第一步:创建 maven 工程
第二步:导入坐标
第三步:编写必要代码(实体类和持久层接口)
第四步:编写 mybatis-config.xml
第五步:编写映射配置文件
第六步:编写测试类
1、持久层接口和持久层接口的映射配置必须在相同的包下。
2、持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名。
3、SQL 语句的配置标签,,,的 id 属性必须和持久层接口的方法名相同。
1.测试查询所有的方法
2.添加方法
3.删除
4.更新
5.根据id查询
6.模糊查询
7.使用聚合函数查询:查询表中有多少条记录数
8.parameterType传递pojo类型参数:根据名字查询
mybatis-config.xml
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/atguigu/dao/UserDao.xml"/>
mappers>
configuration>
UserDao.xml
<mapper namespace="com.atguigu.dao.UserDao">
<resultMap id="map" type="com.atguigu.domain.User">
<id column="id" property="id">id>
<result column="birthday" property="birthday">result>
<result column="sex" property="sex">result>
<result column="address" property="address">result>
<result column="username" property="username">result>
resultMap>
<select id="findAll" resultType="com.atguigu.domain.User">
select * from user;
select>
<insert id="saveUser" parameterType="com.atguigu.domain.User">
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
selectKey>
insert into user(username, birthday, sex, address)
values (#{username}, #{birthday}, #{sex}, #{address});
insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{id};
delete>
<update id="updateUser" parameterType="com.atguigu.domain.User">
update user
set username=#{username},
birthday=#{birthday},
sex=#{sex},
address=#{address}
where id = #{id};
update>
<select id="findById" parameterType="int" resultType="com.atguigu.domain.User">
select * from user where id = #{id};
select>
<select id="findLike" resultType="com.atguigu.domain.User" parameterType="String">
select * from user where username like '%${value}%';
select>
<select id="count" resultType="java.lang.Integer">
select count(*) from user;
select>
<select id="find2" resultType="com.atguigu.domain.User"
parameterType="com.atguigu.domain.MyQuery">
select * from user where username like #{user.username};
select>
mapper>
UserDao
public interface UserDao {
/**
* 查询所有
*/
List<User> findAll();
/**
* 添加
*/
void saveUser(User user);
/**
* 删除
*/
void deleteUser(Integer id);
/**
* 更新
*/
void updateUser(User user);
/**
* 根据id查询
*/
User findById(Integer id);
/**
* 模糊查询
*/
List<User> findLike(String name);
/**
* 使用聚合函数查询
* 查询表中有多少条记录数
*/
Integer count();
/**
* parameterType传递pojo类型参数
* 根据名字查询
*/
List<User> find2(MyQuery query);
}
测试类
public class Test1 {
private InputStream is;
private SqlSession session;
private UserDao userDao;
@Before
public void init() throws Exception {
is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
session = factory.openSession();
userDao = session.getMapper(UserDao.class);
}
@After
public void destory()throws Exception{
session.commit();//默认自动提交为false
session.close();
is.close();
}
/**
* 测试查询所有的方法
*/
@Test
public void test1(){
List<User> users = userDao.findAll();
for (User user:users){
System.out.println(user);
}
}
/**
* 添加方法
*/
@Test
public void test2(){
User user = new User();
user.setUsername("张三");
user.setSex("男");
user.setAddress("黑龙江");
user.setBirthday(new Date());
userDao.saveUser(user);
//保存后返回用户id
System.out.println(user.getId());
}
/**
* 删除
*/
@Test
public void test3(){
userDao.deleteUser(41);
}
/**
* 更新
*/
@Test
public void test4(){
User user = new User();
user.setUsername("李四");
user.setSex("男");
user.setAddress("黑龙江");
user.setBirthday(new Date());
user.setId(49);
userDao.updateUser(user);
}
/**
* 根据id查询
*/
@Test
public void test5(){
User user = userDao.findById(49);
System.out.println(user);
}
/**
* 模糊查询1
* 第一种配置方式#{username}
*/
@Test
public void test6(){
List<User> users = userDao.findLike("%王%");
for (User user :users){
System.out.println(user);
}
}
/**
* 模糊查询2
* 第二种配置方式:${value}固定写法
*/
@Test
public void test7(){
List<User> users = userDao.findLike("王");
for (User user :users){
System.out.println(user);
}
}
/**
* 使用聚合函数查询
* 查询表中有多少条记录数
*/
@Test
public void test8(){
Integer count = userDao.count();
System.out.println(count);
}
/**
* parameterType传递pojo类型参数
* 根据名字查询
*/
@Test
public void test9(){
MyQuery myQuery = new MyQuery();
User user = new User();
user.setUsername("%王%");
myQuery.setUser(user);
List<User> users = userDao.find2(myQuery);
for (User u :users){
System.out.println(u);
}
}
}
configuration 配置
-properties(属性)
--property
-settings(全局配置参数)
--setting
-typeAliases(类型别名)
--typeAliase
--package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
--environment(环境子属性对象)
---transactionManager(事务管理)
---dataSource(数据源)
-databaseIdProvider (数据库厂商标识)
-mappers(映射器)
--mapper
--package
在使用 properties 标签配置时,我们可以采用两种方式指定属性配置。
①第一种,配置放在本配置文件内
<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="root"/>
properties>
②第二种,配置放在单独的配置文件
在 classpath 下定义 db.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=123456
properties标签配置
<properties resource="db.properties">properties>
此时dataSource 标签就变成了引用上面的配置(动态设置)
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
dataSource>
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
包含如下的 setting 设置:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
settings>
在前面我们讲的 Mybatis 支持的默认别名,我们也可以采用自定义别名方式来开发。
第一种,类型别名是为 Java 类型设置一个短的名字,可以方便我们引用某个类。
<typeAliases>
<typeAlias alias="user" type="com.atguigu.domain.User"/>
typeAliases>
第二种,类很多的情况下,可以批量设置别名这个包下的每一个类创建一个默认的别名,就是简单类名小写。
<typeAliases>
<package name="com.atguigu.domain.beans"/>
typeAliases>
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
日期和时间的处理,JDK1.8 以前一直是个头疼的问题。我们通常使用 JSR310 规范领导者 Stephen Colebourne 创建的 Joda-Time 来操作。1.8 已经实现全部的 JSR310 规范了
日期时间处理上,我们可以使用 MyBatis 基于 JSR310(Date and Time API)编写的各种日期时间类型处理器。
MyBatis3.4 以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的,如需注册,需要下载 mybatistypehandlers-jsr310,并通过如下方式注册。
自定义类型转换器
①我们可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型。
②步骤:
实现 org.apache.ibatis.type.TypeHandler 接口或者继承org.apache.ibatis.type.BaseTypeHandler
指定其映射某个 JDBC 类型(可选操作)
在mybatis全局配置文件中注册
environments标签中的default属性指定一个环境的标识符来快速的切换环境。
每种环境使用一个 environment 标签进行配置并指定唯一标识符。
<environments default="oracle">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
dataSource>
environment>
<environments>
作用:用来在 mybatis 初始化的时候,告诉 mybatis 需要引入哪些 Mapper 映射文件。
mapper 属性:
resource : 引入类路径下的文件
url : 引入网络路径或者是磁盘路径下的文件
class : 引入 Mapper 接口
有 SQL 映射文件 , 要求 Mapper 接口与 SQL 映射文件同名同。
没有 SQL 映射文件 , 使用注解在接口的方法上写 SQL 语句。
使用相对于类路径的资源
如:<mapper resource="com/itheima/dao/IUserDao.xml" />
使用 mapper 接口类路径
如:<mapper class="com.itheima.dao.UserDao"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
注册指定包下的所有 mapper 接口
如:<package name="cn.itcast.mybatis.mapper"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
resultType 属性:
用于指定结果集的类型。
parameterType 属性:
用于指定传入参数的类型。
sql 语句中使用#{}字符: 它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。
例如:
<select id="getEmployeeById"
resultType="com.atguigu.mybatis.beans.Employee"
databaseId="mysql">
select * from tbl_employee where id = ${_parameter}
select>
parameterType 属性:
代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称。
sql 语句中使用#{}字符: 它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:
由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。
它用的是 ognl 表达式。
例如:
<insert id="insertEmployee"
parameterType="com.atguigu.mybatis.beans.Employee"
databaseId="mysql">
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
insert>
ognl 表达式:
它是 apache 提供的一种表达式语言,全称是:Object Graphic Navigation Language 对象图导航语言,它是按照一定的语法格式来获取数据的。
语法格式:
使用 #{对象.对象}的方式。
说明:
#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用
getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.
而直接写 username。
若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置useGeneratedKeys=“true”,然后再把keyProperty设置到目标属性上。
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
insert>
而对于不支持自增型主键的数据库(例如 Oracle),则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用。
<insert id="insertEmployee" parameterType="com.atguigu.beans.Employee" databaseId="Oracle">
<selectKey order="BEFORE" keyProperty="id" resultType="integer">
select employee_seq.nextval from dual
selectKey>
insert into orcl_employee(id,last_name,email,gender)
value(#{id},#{lastName},#{email},#{gender})
insert>
新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相
当于我们要在新增后将自动增长 auto_increment 的值返回。
<insert id="saveUser" parameterType="USER">
<selectKey keyColumn="id" keyProperty="id" resultType="int">
select last_insert_id();
selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
insert>
我们在配置文件中没有加入%来作为模糊查询的条件,所以在传入字符串实参时,就需要给定模糊查询的标识%。配置文件中的#{username}也只是一个占位符,所以 SQL 语句显示为“ ?”。
<select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
select * from user where username like #{username}
select>
@Test
public void testFindByName(){
//5.执行查询一个方法
List<User> users = userDao.findByName("%王%");
for(User user : users){
System.out.println(user);
}
}
<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
select * from user where username like '%${value}%'
select>
我们在上面将原来的#{}占位符,改成了${value}。注意如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。
/**
* 测试模糊查询操作
*/
@Test
public void testFindByName(){
//5.执行查询一个方法
List<User> users = userDao.findByName("王");
for(User user : users){
System.out.println(user);
}
}
#{}表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。
${}表示拼接sql串
通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。${} 有 SQL 注入问题。
@Override
public String handleToken(String content) {
Object parameter = context.getBindings().get("_parameter");
if (parameter == null) {
context.getBindings().put("value", null);
} else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
context.getBindings().put("value", parameter);
}
Object value = OgnlCache.getValue(content, context.getBindings());
String srtValue = (value == null ? "" : String.valueOf(value));
checkInjection(srtValue);
return srtValue;
}
这就说明了源码中指定了读取的 key 的名字就是”value”,所以我们在绑定参数时就只能叫 value 的名字了。
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
Pojo 类中包含 pojo。
需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。
MyQuery类
public class MyQuery {
private User user;
private Integer password;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getPassword() {
return password;
}
public void setPassword(Integer password) {
this.password = password;
}
}
配置文件
<select id="find2" resultType="com.atguigu.domain.User"
parameterType="com.atguigu.domain.MyQuery">
select * from user where username like #{user.username};
select>
测试类
/**
* parameterType传递pojo类型参数
* 根据名字查询
*/
@Test
public void test9(){
MyQuery myQuery = new MyQuery();
User user = new User();
user.setUsername("%王%");
myQuery.setUser(user);
List<User> users = userDao.find2(myQuery);
for (User u :users){
System.out.println(u);
}
}
封装结果集
resultType配置结果类型
当他为实体类全限定类名,必须让实体类的属性名与数据库表的列名对应,否则,数据会封装不进去,当然,也存在解决办法。
解决办法:
1.起别名,在sql语句中给数据库表的列名起别名,别名与实体类的属性名一致。
优点:执行效率高
缺点:开发效率低
2.配置resultMap,自定义一个resultMap,在select标签中进行引用。
优点:开发效率高
缺点:执行效率低
<resultMap id="userMap" type="com.atguigu.domain.User">
<id column="id" property="id">id>
<result column="birthday" property="birthday">result>
<result column="sex" property="sex">result>
<result column="address" property="address">result>
<result column="username" property="username">result>
resultMap>
<select id="findAll" resultMap="userMap">
select * from user
select>
1.数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。
2.Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。
解决:将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。
3.向 sql 语句传参数麻烦,因为 sql 语句的 where 条件不一定,可能多也可能少,占位符需要和参数对应。
解决:Mybatis 自动将 java 对象映射至 sql 语句,通过 statement 中的 parameterType 定义输入参数的类型。
4.对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对象解析比较方便。
解决:Mybatis 自动将 sql 执行结果映射至 java 对象,通过 statement 中的 resultType 定义输出结果的类型
public interface UserDao {
/**
* 查询所有
*/
List<User> findAll();
/**
* 添加
*/
void saveUser(User user);
/**
* 删除
*/
void deleteUser(Integer id);
/**
* 更新
*/
void updateUser(User user);
/**
* 根据id查询
*/
User findById(Integer id);
/**
* 模糊查询
*/
List<User> findLike(String name);
/**
* 使用聚合函数查询
* 查询表中有多少条记录数
*/
Integer count();
}
public class UserDaoImpl implements UserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
public List<User> findAll() {
SqlSession session = factory.openSession();
List<User> users = session.selectList("com.atguigu.dao.UserDao.findAll");
session.close();
return users;
}
public void saveUser(User user) {
SqlSession session = factory.openSession();
session.insert("com.atguigu.dao.UserDao.saveUser",user);
session.commit();
session.close();
}
public void deleteUser(Integer id) {
SqlSession session = factory.openSession();
session.delete("com.atguigu.dao.UserDao.deleteUser",id);
session.commit();
session.close();
}
public void updateUser(User user) {
SqlSession session = factory.openSession();
session.update("com.atguigu.dao.UserDao.updateUser",user);
session.commit();
session.close();
}
public User findById(Integer id) {
SqlSession session = factory.openSession();
User user = session.selectOne("com.atguigu.dao.UserDao.findById", id);
session.commit();
session.close();
return user;
}
public List<User> findLike(String name) {
SqlSession session = factory.openSession();
List<User> users = session.selectList("com.atguigu.dao.UserDao.findAll",name);
session.close();
return users;
}
public Integer count() {
SqlSession session = factory.openSession();
Integer o = session.selectOne("com.atguigu.dao.UserDao.count");
session.commit();
session.close();
return o;
}
}
<mapper namespace="com.atguigu.dao.UserDao">
<resultMap id="map" type="com.atguigu.domain.User">
<id column="id" property="id">id>
<result column="birthday" property="birthday">result>
<result column="sex" property="sex">result>
<result column="address" property="address">result>
<result column="username" property="username">result>
resultMap>
<select id="findAll" resultType="com.atguigu.domain.User">
select *
from user;
select>
<insert id="saveUser" parameterType="com.atguigu.domain.User">
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id();
selectKey>
insert into user(username, birthday, sex, address)
values (#{username}, #{birthday}, #{sex}, #{address});
insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete
from user
where id = #{id};
delete>
<update id="updateUser" parameterType="com.atguigu.domain.User">
update user
set username=#{username},
birthday=#{birthday},
sex=#{sex},
address=#{address}
where id = #{id};
update>
<select id="findById" parameterType="int" resultType="com.atguigu.domain.User">
select *
from user
where id = #{id};
select>
<select id="findLike" resultType="com.atguigu.domain.User" parameterType="String">
select * from user where username like '%${value}%';
select>
<select id="count" resultType="java.lang.Integer">
select count(*)
from user;
select>
<select id="find2" resultType="com.atguigu.domain.User"
parameterType="com.atguigu.domain.MyQuery">
select *
from user
where username like #{user.username};
select>
mapper>
public class Test1 {
private InputStream is;
private UserDao userDao;
@Before
public void init()throws Exception {
is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
userDao=new UserDaoImpl(factory);
}
@After
public void destory()throws Exception{
is.close();
}
/**
* 测试查询所有的方法
*/
@Test
public void test1(){
List<User> users = userDao.findAll();
for (User user:users){
System.out.println(user);
}
}
/**
* 添加方法
*/
@Test
public void test2(){
User user = new User();
user.setUsername("张三");
user.setSex("男");
user.setAddress("黑龙江");
user.setBirthday(new Date());
userDao.saveUser(user);
//保存后返回用户id
System.out.println(user.getId());
}
/**
* 删除
*/
@Test
public void test3(){
userDao.deleteUser(41);
}
/**
* 更新
*/
@Test
public void test4(){
User user = new User();
user.setUsername("李四");
user.setSex("男");
user.setAddress("黑龙江");
user.setBirthday(new Date());
user.setId(49);
userDao.updateUser(user);
}
/**
* 根据id查询
*/
@Test
public void test5(){
User user = userDao.findById(49);
System.out.println(user);
}
/**
* 模糊查询1
* 第一种配置方式#{username}
*/
@Test
public void test6(){
List<User> users = userDao.findLike("%王%");
for (User user :users){
System.out.println(user);
}
}
/**
* 模糊查询2
* 第二种配置方式:${value}固定写法
*/
@Test
public void test7(){
List<User> users = userDao.findLike("王");
for (User user :users){
System.out.println(user);
}
}
/**
* 使用聚合函数查询
* 查询表中有多少条记录数
*/
@Test
public void test8(){
Integer count = userDao.count();
System.out.println(count);
}
}
Mybatis后续的学习:
mybatis 事务 | 动态SQL | 多表查询:https://blog.csdn.net/weixin_45606067/article/details/107368642
mybatis延迟加载 | 缓存机制详解:https://blog.csdn.net/weixin_45606067/article/details/107368706
mybatis 注解开发版:https://blog.csdn.net/weixin_45606067/article/details/107368743
mybatis 逆向工程的使用:https://blog.csdn.net/weixin_45606067/article/details/107368781
pageHelper分页技术:https://blog.csdn.net/weixin_45606067/article/details/107368847