mybatis的学习笔记

时间:2023-03-09 02:24:43
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的流程图:

mybatis的学习笔记

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

mybatis的学习笔记

这张表已经被我使用过多次,插入一些数据了。

接下来,第一件事,导包。(会maven的童鞋自己去百度下pom.xml的配置,这个小案例我这里就不用maven了)

mybatis的学习笔记

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

mybatis的学习笔记

先来讲config这个目录下:

mybatis的学习笔记

全局配置文件: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的学习笔记

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定义输出结果的类型。