主要內容
1、對原生態(tài)jdbc程序(單獨使用jdbc開發(fā))問題總結
2、mybatis框架原理
3、mybatis入門程序
4、mybatis開發(fā)dao兩種方法
5、mybatis配置文件SqlMapConfig.xml
6、mybatis核心
7、mybatis的動態(tài)sql
1、原生態(tài)jdbc程序中問題總結
下面的代碼,有很多問題,總結如下:
public class JdbcTest {
public static void main(String[] args) {
//數(shù)據(jù)庫連接
Connection connection = null;
//預編譯的Statement,使用預編譯的Statement提高數(shù)據(jù)庫性能
PreparedStatement preparedStatement = null;
//結果 集
ResultSet resultSet = null;
try {
//加載數(shù)據(jù)庫驅動
Class.forName("com.mysql.jdbc.Driver");
//通過驅動管理類獲取數(shù)據(jù)庫鏈接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mysql");
//定義sql語句 ?表示占位符
String sql = "select * from user where username = ?";
//獲取預處理statement
preparedStatement = connection.prepareStatement(sql);
//設置參數(shù),第一個參數(shù)為sql語句中參數(shù)的序號(從1開始),第二個參數(shù)為設置的參數(shù)值
preparedStatement.setString(1, "王五");
//向數(shù)據(jù)庫發(fā)出sql執(zhí)行查詢,查詢出結果集
resultSet = preparedStatement.executeQuery();
//遍歷查詢結果集
while(resultSet.next()){
System.out.println(resultSet.getString("id")+" "+resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//釋放資源
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
1、數(shù)據(jù)庫連接,使用時就創(chuàng)建,不使用立即釋放,對數(shù)據(jù)庫進行頻繁連接開啟和關閉,造成數(shù)據(jù)庫資源浪費,影響 數(shù)據(jù)庫性能。
設想:使用數(shù)據(jù)庫連接池管理數(shù)據(jù)庫連接。
2、將sql語句硬編碼到java代碼中,如果sql 語句修改,需要重新編譯java代碼,不利于系統(tǒng)維護。
設想:將sql語句配置在xml配置文件中,即使sql變化,不需要對java代碼進行重新編譯。
3、向preparedStatement中設置參數(shù),對占位符號位置和設置參數(shù)值,硬編碼在java代碼中,不利于系統(tǒng)維護。
設想:將sql語句及占位符號和參數(shù)全部配置在xml中。
4、從resutSet中遍歷結果集數(shù)據(jù)時,存在硬編碼,將獲取表的字段進行硬編碼,,不利于系統(tǒng)維護。
設想:將查詢的結果集,自動映射成java對象。
2、mybatis框架
2-1 mybatis是什么?
mybatis是一個持久層的框架,是apache下的頂級項目。
mybatis讓程序將主要精力放在sql上,通過mybatis提供的映射方式,自由靈活生成(半自動化,大部分需要程序員編寫sql)滿足需要sql語句。
mybatis可以將向 preparedStatement中的輸入?yún)?shù)自動進行輸入映射,將查詢結果集靈活映射成java對象。(輸出映射)
2-2 mybatis框架

2-3 mybatis使用步驟(基礎方式1)

1 讀取SqlMapConfig.xml文件,其中配置了Mybatis的基本信息
private SqlSessionFactory sqlSessionFactory;
// 此方法是在執(zhí)行testFindUserById之前執(zhí)行
@Before
public void setUp() throws Exception {
// 創(chuàng)建sqlSessionFactory
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 創(chuàng)建會話工廠,傳入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
}
2 配置mybatis的運行環(huán)境,數(shù)據(jù)源、事務等。
<configuration>
<!-- 加載屬性文件 -->
<properties resource="db.properties">
<!--properties中還可以配置一些屬性名和屬性值 -->
<!-- <property name="jdbc.driver" value=""/> -->
</properties>
<!-- 和spring整合后 environments配置將廢除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務管理,事務控制由mybatis-->
<transactionManager type="JDBC" />
<!-- 數(shù)據(jù)庫連接池,由mybatis管理-->
<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>
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
</configuration>
3 新建xml的sql對象
<mapper namespace="test">
<!--如果輸入 參數(shù)是簡單類型,#{}中的參數(shù)名可以任意,可以value或其它名稱-->
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
select * from user where id = #{value}
</select>
<!-- ${value}:接收輸入 參數(shù)的內容,如果傳入類型是簡單類型,${}中只能使用value
返回值是list還是單個值,通過接口的返回值確定
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User">
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address})
</insert>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>
<update id="updateUser" parameterType="cn.itcast.mybatis.po.User">
update user set sex=#{sex}
where id=#{id}
</update>
</mapper>
4 定義接口和實現(xiàn)類
接口
public interface UserDao {
//根據(jù)id查詢用戶信息
public User findUserById(int id) throws Exception;
//根據(jù)用戶名列查詢用戶列表
public List<User> findUserByName(String name) throws Exception;
//添加用戶信息
public void insertUser(User user) throws Exception;
//刪除用戶信息
public void deleteUser(int id) throws Exception;
public void updateUser(User user) throws Exception;
}
實現(xiàn)類
// 需要向dao實現(xiàn)類中注入SqlSessionFactory
// 這里通過構造方法注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
public User findUserById(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", id);
// 釋放資源
sqlSession.close();
return user;
}
public List<User> findUserByName(String name) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("test.findUserByName", name);
// 釋放資源
sqlSession.close();
return list;
}
public void insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//執(zhí)行插入操作
sqlSession.insert("test.insertUser", user);
// 提交事務
sqlSession.commit();
// 釋放資源
sqlSession.close();
}
public void deleteUser(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//執(zhí)行插入操作
sqlSession.delete("test.deleteUser", id);
// 提交事務
sqlSession.commit();
// 釋放資源
sqlSession.close();
}
public void updateUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//執(zhí)行插入操作
sqlSession.update("test.updateUser", user);
// 提交事務
sqlSession.commit();
// 釋放資源
sqlSession.close();
}
3 mybatis使用方式(2)---- mapper代理
可以發(fā)現(xiàn)上述的接口實現(xiàn)類中存在大量的重復代碼
所以Mybatis還提供直接通過xml來執(zhí)行的sql語句的方式
1 測試類代碼
@Test
public void findUserId() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
//創(chuàng)建UserMapper對象,mybatis自動生成mapper代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//調用userMapper的方法
User user = userMapper.findUserId(1);
System.out.println(user);
}
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
<select id="findUserId" parameterType="int" resultType="cn.itcast.mybatis.po.User">
select * from user where id=#{value}
</select>
</mapper>
上面的測試類代碼是可以直接通過匹配xml中的id調用xml的sql語句執(zhí)行查詢的
User user = userMapper.findUserId(1);
,簡化了實現(xiàn)類的書寫。
開發(fā)規(guī)范:
1、在mapper.xml中namespace等于mapper接口地址
2、mapper.java接口中的方法名和mapper.xml中statement的id一致
3、mapper.java接口中的方法輸入?yún)?shù)類型和mapper.xml中statement的parameterType指定的類型一致。
4、mapper.java接口中的方法返回值類型和mapper.xml中statement的resultType指定的類型一致。
總結:
以上開發(fā)規(guī)范主要是對下邊的代碼進行統(tǒng)一生成:
User user = sqlSession.selectOne("test.findUserById", id);
sqlSession.insert("test.insertUser", user);
4 SqlMapConfig.xml的配置
mybatis的全局配置文件SqlMapConfig.xml,配置內容如下:
properties(屬性)
settings(全局配置參數(shù))
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環(huán)境集合屬性對象)
environment(環(huán)境子屬性對象)
transactionManager(事務管理)
dataSource(數(shù)據(jù)源)
mappers(映射器)
4-1 properties屬性
可將數(shù)據(jù)庫連接參數(shù)單獨配置在db.properties中,只需要在SqlMapConfig.xml中加載db.properties的屬性值。
在SqlMapConfig.xml中就不需要對數(shù)據(jù)庫連接參數(shù)硬編碼。
將數(shù)據(jù)庫連接參數(shù)只配置在db.properties中,原因:方便對參數(shù)進行統(tǒng)一管理,其它xml可以引用該db.properties。
<!-- 加載屬性文件 -->
<properties resource="db.properties">
<!--properties中還可以配置一些屬性名和屬性值 -->
<!-- <property name="jdbc.driver" value=""/> -->
</properties>
建議:
不要在properties元素體內添加任何屬性值,只將屬性值定義在properties文件中。
在properties文件中定義屬性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX
4-2 settings全局參數(shù)配置
mybatis框架在運行時可以調整一些運行參數(shù)。
比如:開啟二級緩存、開啟延遲加載。。
全局參數(shù)將會影響mybatis的運行行為。
4-3 typeAliases(別名)重點
在mapper.xml中,定義很多的statement,statement需要parameterType指定輸入?yún)?shù)的類型、需要resultType指定輸出結果的映射類型。
如果在指定類型時輸入類型全路徑,不方便進行開發(fā),可以針對parameterType或resultType指定的類型定義一些別名,在mapper.xml中通過別名定義,方便開發(fā)。
<!-- 別名定義 -->
<typeAliases>
<!-- 針對單個別名定義
type:類型的路徑
alias:別名
-->
<typeAlias type="cn.itcast.mybatis.po.User" alias="user"/>
<!-- 批量別名定義
指定包名,mybatis自動掃描包中的po類,自動定義別名,別名就是類名(首字母大寫或小寫都可以)
-->
<package name="cn.itcast.mybatis.po"/>
</typeAliases>
4-4 mappers(映射配置)
1 通過resource加載單個映射文件
2 通過mapper接口加載單個mapper
3 批量加載mapper(推薦使用)
<mappers>
<!-- <mapper resource="sqlmap/User.xml"/> -->
<!--通過resource方法一次加載一個映射文件 -->
<!-- <mapper resource="mapper/UserMapper.xml"/> -->
<!-- 通過mapper接口加載單個 映射文件
遵循一些規(guī)范:需要將mapper接口類名和mapper.xml映射文件名稱保持一致,且在一個目錄 中
上邊規(guī)范的前提是:使用的是mapper代理方法
-->
<!-- <mapper class="cn.itcast.mybatis.mapper.UserMapper"/> -->
<!-- 批量加載mapper
指定mapper接口的包名,mybatis自動掃描包下邊所有mapper接口進行加載
遵循一些規(guī)范:需要將mapper接口類名和mapper.xml映射文件名稱保持一致,且在一個目錄 中
上邊規(guī)范的前提是:使用的是mapper代理方法
-->
<package name="cn.itcast.mybatis.mapper"/>
</mappers>
5 輸入映射(parameterType)和輸出映射(resultType)
輸入映射:
通過parameterType指定輸入?yún)?shù)的類型,類型可以是簡單類型、hashmap、pojo的包裝類型。
注意:
1、使用resultType進行輸出映射,只有查詢出來的列名和pojo中的屬性名一致,該列才可以映射成功。
2、如果查詢出來的列名和pojo中的屬性名全部不一致,沒有創(chuàng)建pojo對象。
3、只要查詢出來的列名和pojo中的屬性有一個一致,就會創(chuàng)建pojo對象,不一致的屬性的值為null。
輸出映射:
使用resultType進行輸出映射,只有查詢出來的列名和pojo中的屬性名一致,該列才可以映射成功。
如果查詢出來的列名和pojo中的屬性名全部不一致,沒有創(chuàng)建pojo對象。
只要查詢出來的列名和pojo中的屬性有一個一致,就會創(chuàng)建pojo對象,不一致的屬性的值為null。
<!-- 用戶信息綜合查詢
#{userCustom.sex}:取出pojo包裝對象中性別值
${userCustom.username}:取出pojo包裝對象中用戶名稱
-->
<select id="findUserList" parameterType="cn.itcast.mybatis.po.UserQueryVo"
resultType="cn.itcast.mybatis.po.UserCustom">
SELECT * FROM USER
</select>
@Test
public void testFindUserList() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//創(chuàng)建UserMapper對象,mybatis自動生成mapper代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//創(chuàng)建包裝對象,設置查詢條件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
//由于這里使用動態(tài)sql,如果不設置某個值,條件不會拼接在sql中
// userCustom.setSex("1");
userCustom.setUsername("小明");
//傳入多個id
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(10);
ids.add(16);
//將ids通過userQueryVo傳入statement中
userQueryVo.setIds(ids);
userQueryVo.setUserCustom(userCustom);
//調用userMapper的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);
System.out.println(list);
}
6 動態(tài)sql
mybatis核心。對sql語句進行靈活操作,通過表達式進行判斷,對sql進行靈活拼接、組裝。
nobibi,show you my code
@Test
public void findUserCount() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//創(chuàng)建UserMapper對象,mybatis自動生成mapper代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//創(chuàng)建包裝對象,設置查詢條件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("張三豐");
userQueryVo.setUserCustom(userCustom);
int count = userMapper.findUserCount(userQueryVo);
System.out.println(count);
}
<!-- 定義sql片段
id:sql片段的唯 一標識
經驗:是基于單表來定義sql片段,這樣話這個sql片段可重用性才高
在sql片段中不要包括 where
-->
<sql id="query_user_where">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username LIKE '%${userCustom.username}%'
</if>
</if>
</sql>
<!-- 用戶信息綜合查詢總數(shù)
parameterType:指定輸入類型和findUserList一樣
resultType:輸出結果類型
-->
<select id="findUserCount" parameterType="cn.itcast.mybatis.po.UserQueryVo" resultType="int">
SELECT count(*) FROM USER
<!--
where可以自動去掉條件中的第一個and
-->
<where>
<!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前邊加namespace -->
<include refid="query_user_where"></include>
<!-- 在這里還要引用其它的sql片段 -->
</where>
</select>
感覺這個功能很NP,要善用。