mybatis的学习笔记
前几天学习了mybatis,今天来复习一下它的内容。
mybatis是一个基于Java的持久层框架,那就涉及到数据库的操作。首先来提出第一个问题:java有jdbc连接数据库,我们为什么还要使用框架呢?要回答这个问题,首先来看一下jdbc是怎样编程的。
private static String sql = "SELECT * FROM USER WHERE username = ?";
public static void main(String[] args) throws SQLException {
//数据库连接
Connection connection = null;
//预编译statement
//好处:防止 sql注入,提高数据的性能
PreparedStatement preparedStatement = null;
//结果集
ResultSet resultSet = null;
try {
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//连接数据库
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "mysql");
//构造preparedStatement
preparedStatement = connection.prepareStatement(sql);
//向preparedStatement中占位符的位置设置参数
preparedStatement.setString(1, "张三");
//发起数据库查询请求,得到结果集
resultSet = preparedStatement.executeQuery();
//遍历查询结果
while(resultSet.next()){
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
Date birthday = resultSet.getDate("birthday");
System.out.println(id+" "+username+" "+birthday);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
if(resultSet!=null){
resultSet.close();
}
if(preparedStatement!=null){
preparedStatement.close();
}
if(connection!=null){
connection.close();
}
}
}
}
从上面代码总结一下jdbc编程中的一些问题:
1、 将sql语句硬编码到java代码中,如果修改sql语句,需要修改java代码,重新编译。系统可维护性不高。
设想如何解决?
能否将sql单独 配置在配置文件中。
2、 数据库连接频繁开启和释放,对数据库的资源是一种浪费。
设想如何解决?
使用数据库连接池管理数据库连接。
3、 向preparedStatement中占位符的位置设置参数时,存在硬编码(占位符的位置,设置的变量值)
设想如何解决?
能否也通过配置的方式,配置设置的参数,自动进行设置参数。
4、 解析结果集时存在硬编码(表的字段名、字段的类型)
设想如何解决?
能否将查询结果集映射成java对象。
先来看看Mybatis的流程图:

以一个具体的案例来说明,先来看看表:

这张表已经被我使用过多次,插入一些数据了。
接下来,第一件事,导包。(会maven的童鞋自己去百度下pom.xml的配置,这个小案例我这里就不用maven了)

项目的整体目录是这个样子的:

先来讲config这个目录下:

全局配置文件:SqlMapConfig.xml文件内容:
数据库运行环境(和spring整合则去掉这部分)
Mapper映射文件。
实现延迟加载,打开二级缓存。
定义别名。
代码如下:
<?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">
<configuration>
<!-- 加载数据库连接参数配置文件 -->
<properties resource="db.properties" /> <!-- 全局配置参数 --> <settings>
<!-- 实现延迟加载 -->
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" /> <!-- 打开二级缓存开关 -->
<setting name="cacheEnabled" value="true"/>
</settings> <!-- 定义别名 -->
<typeAliases>
<!-- 单个别名定义 type:pojo的路径 alias:别名的名称 -->
<!-- <typeAlias type="com.mybatis.po.User" alias="user"/> -->
<!-- 批量别名定义 name:指定包名,将包下边的所有pojo定义别名 ,别名为类名(首字母大写或小写都行) -->
<package name="com.mybatis.po" />
</typeAliases> <!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<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> <!-- 配置mapper映射文件 -->
<mappers>
<!-- resource方式 在UserMapper.xml,定义namespace为mapper接口的地址,映射文件通过namespace找到对应的mapper接口文件 -->
<!-- <mapper resource="sqlmap/UserMapper.xml" /> -->
<!-- class方式 class:指定 mapper接口的地址 遵循规则:将mapper.xml和mapper.java文件放在一个目录
且文件名相同 -->
<!-- <mapper class="com.mybatis.mapper.UserMapper"/> --> <!--批量mapper扫描 遵循规则:将mapper.xml和mapper.java文件放在一个目录 且文件名相同 -->
<package name="com.mybatis.mapper" /> </mappers>
</configuration>
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=202011
log4j.properties:使用debug。
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
po类:user.java 要存入二级缓存,所以序列化了。
package com.mybatis.po;
import java.io.Serializable;
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private String username;// 用户姓名
private String age;
private String sex;// 性别
private String address;// 地址
private String detail;// 详细信息
public User() {
}
public User(String username) {
super();
this.username = username;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
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;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", age=" + age
+ ", sex=" + sex + ", address=" + address + ", detail="
+ detail + "]";
}
}
配置mybatis的mapper映射文件:
userMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace命名空间特殊作用: 如果使用mapper动态代理方法,这里就需要配置mapper接口地址--> <mapper namespace="com.mybatis.mapper.UserMapper">
<!-- 根据用户id查询一条记录(返回单条记录) -->
<!--
select标签表示sql查询,内容会封装到Mapped Statement中。
可以将这个select标签称为一个Statement
id:Statement的id,用于标识select中定义的 sql,id是在同一个命名空间中不允许重复
#{}:表示一个占位符,避免sql注入
parameterType:表示输入参数的类型
resultType:表示输出 结果集单条记录映射的java对象类型,select查询的字段名和resultType中属性名一致,才能映射成功。
#{value}:value表示parameter输入参数的变量,如果输入参数是简单类型,使用#{}占位符,变量名可以使用value或其它的名称 -->
<select id="findUserByName" parameterType="String" resultType="User" useCache="false"> SELECT * FROM USER WHERE username = #{username} </select> <select id="findUserById" parameterType="int" resultType="User"> SELECT * FROM USER WHERE id= #{id} </select> <!-- 查询用户列表(返回list集合) -->
<!--
不管结果集查询一条还是多条,resultType指定结果集单条记录映射的java对象类型
${}:表示sql拼接,相当于sql字符串拼接,无法避免sql注入
${value}:value表示parameter输入参数的变量,如果输入参数是简单类型,使用${}拼接符,变量名必须使用value
${value}直接 将value获取到拼接在sql中,value值不加任何修饰
-->
<select id="findUserList" parameterType="java.lang.String" resultType="User" >
SELECT * FROM USER WHERE username like '%${value}%'
</select> <!-- 添加用户
parameterType:如果parameterType指定 是pojo,在#{}中指定 pojo的属性名获取该pojo的属性值
-->
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id"> <!--
useGeneratedKeys设置true表明要mybatis获取由数据库自动生成的主键
keyProperty:将主键设置到pojo中哪个属性中
order:selectKey中sql执行的时机
resultType:selectKey中sql执行的结果类型
LAST_INSERT_ID:是insert后获取自增主键值
-->
<!--
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
-->
insert into user(username,sex,address,detail)
values(#{username},#{sex},#{address},#{detail})
</insert> <!-- 根据主键删除用户 --> <delete id="deleteUser" parameterType="java.lang.String">
delete from user where username =#{username}
</delete> <!-- 根据主键用户更新
更新传入输入参数见容:id和更新的信息
-->
<update id="updateUser" parameterType="User" >
update user set username=#{username},sex=#{sex},address=#{address},detail=#{detail} where id=#{id}
</update> <cache/>
</mapper>
userMapper.java:
package com.mybatis.mapper;
import java.util.List;
import com.mybatis.po.User;
public interface UserMapper {
//根据用户id查询用户信息
public User findUserById(int id) throws Exception;
//根据用户名字查询信息
public User findUserByName(String username) throws Exception;
//查询用户列表
public List<User> findUserList(String username)throws Exception;
public void deleteUser(String username)throws Exception;
public int insertUser(User user)throws Exception;
public void updateUser(User user)throws Exception;
}
Test.java:
package com.mybatis.mapper; import java.io.InputStream;
import java.util.List; 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.Before;
import org.junit.Test; import com.mybatis.po.User; public class UserMapperTest { // 会话工厂
private SqlSessionFactory sqlSessionFactory; @Before
public void setUp() throws Exception {
// 加载配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource); // 根据mytais的配置创建SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //sqlSessionFactory.getConfiguration().addMapper(UserMapper.class);
} @Test
public void testFindUserByName() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过sqlSession创建代理对象(接口的实现类对象)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user= userMapper.findUserByName("张小三");
System.out.println(user);
} @Test
public void testFindUserList() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过sqlSession创建代理对象(接口的实现类对象)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> list = userMapper.findUserList("d");
for(User x:list){
System.out.println(x.getUsername());
} } /*
由于我的这个user表被其他表的外键连接,所以这里暂不进行删除操作。
@Test
public void deleteUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过sqlSession创建代理对象(接口的实现类对象)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.deleteUser("duyu");
sqlSession.commit();
sqlSession.close(); }
*/ @Test
public void insertUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过sqlSession创建代理对象(接口的实现类对象)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user=new User("2017-3-12");
user.setAddress("四川");
int z=userMapper.insertUser(user);
sqlSession.commit();
sqlSession.close();
System.out.println(z); } @Test
public void updateUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过sqlSession创建代理对象(接口的实现类对象)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user=userMapper.findUserByName("duu");
user.setAddress("北京");
user.setUsername("Eminem");
userMapper.updateUser(user);
sqlSession.commit();
sqlSession.close(); } }
执行完操作后表如下:

mybatis对jdbc编程问题的解决:
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定义输出结果的类型。
mybatis的学习笔记的更多相关文章
- MyBatis:学习笔记(4)——动态SQL
MyBatis:学习笔记(4)——动态SQL 如果使用JDBC或者其他框架,很多时候需要你根据需求手动拼装SQL语句,这是一件非常麻烦的事情.MyBatis提供了对SQL语句动态的组装能力,而且他只有 ...
- 关于mybatis的学习笔记
配置文件 贴出mybatis的配置文件,这里mybatis还未与spring做整合: <?xml version="1.0" encoding="UTF-8&quo ...
- MyBatis 3学习笔记
MyBatis 3 一.MyBatis简介 优秀的持久层框架,支持支持自定义 SQL.存储过程以及高级映射,专注于SQL的编写. 为什么不使用工具类进行数据库操作: 功能简单,sql语句编写在 ...
- mybatis缓存学习笔记
mybatis有两级缓存机制,一级缓存默认开启,可以在手动关闭:二级缓存默认关闭,可以手动开启.一级缓存为线程内缓存,二级缓存为线程间缓存. 一提缓存,必是查询.缓存的作用就是查询快.写操作只能使得缓 ...
- 3、MyBatis.Net学习笔记之增删改
增删改之前先说一下笔记1里提到的一个无法创建ISqlMapper对象的问题. <resultMaps> <resultMap id="FullResultMap" ...
- MyBatis基础学习笔记--摘录
1.MyBatis是什么? MyBatis源自于IBatis,是一个持久层框架,封装了jdbc操作数据库的过程,使得开发者只用关心sql语句,无需关心驱动加载.连接,创建statement,手动设置参 ...
- MyBatis基础学习笔记--自总结
一.MyBatis和jdbc的区别 jdbc的过程包括: 1.加载数据库驱动. 2.建立数据库连接. 3.编写sql语句. 4.获取Statement:(Statement.PrepareStatem ...
- Mybatis进阶学习笔记——动态代理方式开发Dao接口、Dao层(推荐第二种)
1.原始方法开发Dao Dao接口 package cn.sm1234.dao; import java.util.List; import cn.sm1234.domain.Customer; pu ...
- MyBatis入门学习笔记(一)
一.什么是MyBatis? Mybatis是一种“半自动化”的ORM实现,支持定制化 SQL.存储过程以及高级映射. 二.hibernate和mybatis对比 共同:采用ORM思想解决了实体和数据库 ...
随机推荐
- OVS vxlan 底层结构分析 - 每天5分钟玩转 OpenStack(148)
上一节创建了 vxlan100_net 并部署 instance,今天我们来分析底层网络结构. 控制节点 执行 ovs-vsctl show: br-int br-int 连接了如下 port: ta ...
- UI进阶 即时通讯之XMPP登录、注册
1.XMPP环境搭建 http://www.cnblogs.com/fearlessyyp/p/5506644.html 第一次打开可能会有点儿慢,图片很多,步骤很详细,祝搭建成功. 2.工程中添加X ...
- EntityFramewok Core 1.1连接MSSql数据库详解
最近在研究ASP.NET Core,其中就用到了Entity Framework Core,对于Entity Framework Core连接SqlServer数据库,使用Code Frist创建数据 ...
- matlab for循环的三种类型
学习了一半了,发现一个好网站,就是我想写这篇博客用的,网络真是个好东西!纪念下国庆啦 网址:http://www.yiibai.com/matlab/matlab_for_loop.html ---- ...
- 初学bootstrap ---栅格系统
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 读书笔记 effective c++ Item 14 对资源管理类的拷贝行为要谨慎
1. 自己实现一个资源管理类 Item 13中介绍了 “资源获取之时也是初始化之时(RAII)”的概念,这个概念被当作资源管理类的“脊柱“,也描述了auto_ptr和tr1::shared_ptr是如 ...
- Color.js 增强你对颜色的控制
Color.js是一个能加强前端开发中对颜色处理的第三方库. 假设你已经基本了解色彩通道.色彩空间.色相.饱和度.亮度.不透明度等概念.当然了,毕竟前端算是半只脚踏进设计领域了,相信这些概念难不到你. ...
- Extjs 数据代理
Ext.data.proxy.Proxy 代理类的根类 客户端代理: 1.LocalStorageProxy:将数据存储在localStorage中,此种方式可以持久的将数据存储在客户端 要使用代理, ...
- Linux下ifort的安装记录
首先进入网址https://software.intel.com/en-us/qualify-for-free-software/student 下载Intel Parallel Studio XE ...
- 从C#到TypeScript - async await
总目录 从C#到TypeScript - 类型 从C#到TypeScript - 高级类型 从C#到TypeScript - 变量 从C#到TypeScript - 接口 从C#到TypeScript ...