MyBatis学习手记二
前:MyBatis官方学习(中文)文档 http://mybatis.github.io/mybatis-3/zh/index.html
一,首先,要使用MyBatis必须使用官方提供的MyBatis的JAR包
链接:https://github.com/mybatis/mybatis-3/releases
这里使用的数据库是MySQL,所以还需要Mysql的驱动包、
二,看MyBatis官方介绍,说MyBatis支持一级缓存,二级缓存。这里才是我真正要学习MyBatis的原因来源。
要知道,如果在项目中,在Dao层中使用了缓存机制的话,你的数据库压力将会大大优化。你的程序的响应速度也将大大提升。
在MyBatis中,一级缓存其实已经默认打开了、
public static void main(String[] args) throws Exception
{
SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.selectUserById(1);
User user2 = userMapper.selectUserById(1);
System.out.println(user.getName());
System.out.println(user2.getName());
session.close();
}
这里,我们只新建了一个SqlSession,然后实例化一个UserMapper 查询两次。
然后我们可以看一下控制台打印的BUG
DEBUG [main] - Logging initialized using 'org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Openning JDBC Connection
DEBUG [main] - Created connection 27187756.
DEBUG [main] - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@19eda2c]
DEBUG [main] - ==> Preparing: select * from user where id = ?
DEBUG [main] - ==> Parameters: 1(Integer)
xiaolei
xiaolei
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@19eda2c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@19eda2c]
DEBUG [main] - Returned connection 27187756 to pool.
从这里我就能看见,虽然我们在代码中执行了两次查询,可是真正从数据库中获取数据的操作,却只有一次。
Preparing: select * from user where id = ?
三、也就是说,这里一级缓存,我们可以不用去考虑。然后我们重点考虑一下二级缓存
通过查询资料,我发现,二级缓存其实也不是那么复杂、只需要在配置文件中配置一下,就OK了、
MyBatis-Config.xml
<?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>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" />
<property name="username" value="root"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.xcode.beens.mapperInterfaces.UserMapper"/>
</mappers>
</configuration>
我们发现。这个配置文件与之前的配置文件,多了这么个东西
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
好吧,当我发现只要配置这么一段话的时候,劳资真想说:'吓死宝宝了'
然后我再继续测试,发现并没什么区别。然后有些操作还会报错
org.apache.ibatis.cache.CacheException: Error serializing object.
Cause: java.io.NotSerializableException:
当出现这个异常的时候,我就知道,并没有那么简单。
然后我查阅资料,发现,原来是我的Been有问题,原来要实现二级缓存,就必须实现可序列化接口:java.io.Serializable
将User.java实现一下这个接口:
package com.xcode.beens;
import java.io.Serializable;
public class User implements Serializable
{
private static final long serialVersionUID = 8942594370466951584L;
private int id;
private String name;
private String sex;
private String address;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
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 static void main(String[] args) throws Exception
{
SqlSession session = sqlSessionFactory.openSession();
SqlSession session2 = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
UserMapper userMapper2 = session2.getMapper(UserMapper.class);
User user = userMapper.selectUserById(1);
session.commit();//这里一定要提交一下,否则也会查询两次
User user2 = userMapper2.selectUserById(1);
System.out.println(user.getName());
System.out.println(user2.getName());
session.close();
session2.close();
}
这段代码中我们可以看到,我在这里实例化了两个 SqlSession 然后不同的SqlSession实例化了不同的 UserMapper,
两个UserMapper执行同样的操作,都是对数据库进行查询。,这时我们看一下控制台日志:
DEBUG [main] - Logging initialized using 'org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - Cache Hit Ratio [com.xcode.beens.mapperInterfaces.UserMapper]: 0.0
DEBUG [main] - Openning JDBC Connection
DEBUG [main] - Created connection 12644844.
DEBUG [main] - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@c0f1ec]
DEBUG [main] - ==> Preparing: select * from user where id = ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - Cache Hit Ratio [com.xcode.beens.mapperInterfaces.UserMapper]: 0.5
xiaolei
xiaolei
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@c0f1ec]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@c0f1ec]
DEBUG [main] - Returned connection 12644844 to pool.
我们这回看见,虽然我们代码里查询了两次,可是真正去数据库中查询,我们却只查询了一次,也就是说,我们第二次是读的缓存。
注:在之前我用了注解的方式,发现缓存根本没有起作用,然后我查了一下,没有找到使用注解就使用二级缓存的方式
也就是说,这里必须使用UserMapper.xml配置文件配置,才能使用二级缓存。
MyBatis-Config.xml 需要修改为:
<?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>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 这里需要注意,这个typeAliases不能放在 environments 这个节点的下面,否则会报错 -->
<typeAliases>
<typeAlias alias="User" type="com.xcode.beens.User"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" />
<property name="username" value="root"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xcode/beens/mapperInterfaces/UserMapper.xml"/>
</mappers>
</configuration>
我们注意到,修改的地方就是
<mappers>
<mapper resource="com/xcode/beens/mapperInterfaces/UserMapper.xml"/>
</mappers>
然后我们在 com.xcode.beens.mapperInterfaces 包下新建 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">
<mapper namespace="com.xcode.beens.mapperInterfaces.UserMapper">
<cache />
<!-- 这儿的resultType是配置在mybatis-config.xml中得别名 -->
<select id="selectUserById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
<select id="selectUsersByName" parameterType="string" resultMap="resultListUser">
select * from user where name = #{name}
</select>
<!-- 为了返回list 类型而定义的returnMap -->
<resultMap type="User" id="resultListUser">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="sex" property="sex" />
<result column="address" property="address" />
</resultMap>
<insert id="insertUser" parameterType="User">
INSERT INTO `user` (`name`, `sex`, `address`) VALUES (#{name},#{sex},#{address})
</insert>
<delete id="deleteUserByID" parameterType="int">
delete from user where id = #{id}
</delete>
</mapper>
我们注意一行:
<mapper namespace="com.xcode.beens.mapperInterfaces.UserMapper">
namespace配置的就是Mapper接口的 全限定名。
再我们修改一下 UserMapper.java
package com.xcode.beens.mapperInterfaces;
import java.util.List;
import com.xcode.beens.User;
public interface UserMapper
{
public User selectUserById(int id);
public List<User> selectUsersByName(String name);
public void insertUser(User user);
public void deleteUserByID(int id);
}
我们这里将前面所有的注解都删了,注解的SQL语句配置到UserMapper.xml文件中了。
好了,收工!再执行一下刚才的 Main , 二级缓存使用成功!
这里很多都没有详细讲,比如那个Mapper配置文件。以及返回结果集是多条的时候,怎么转换成List的。我也是刚学,写博客只是为了记录下来以便自己以后忘记了,能迅速拿起来。