双人在线音乐播放器SQL操作、播放删除功能及代码优化咨询
一、歌曲播放完成后的SQL删除实现
要实现播放完成后同步删除ListBox和SQL数据库中的歌曲,需分两步执行:
1. SQL端删除逻辑
通过参数化的DELETE语句删除Playlist表中对应ID的歌曲记录,避免SQL注入风险:
private void DeletePlayedSong(int songId) { // 1. 删除SQL Playlist表中的目标歌曲 using (MySqlCommand deleteCmd = new MySqlCommand("DELETE FROM playlist WHERE ID = @SongId", MyCon)) { deleteCmd.Parameters.AddWithValue("@SongId", songId); deleteCmd.ExecuteNonQuery(); } // 2. 从ListBox移除对应歌曲(假设LB_Playlist存储歌曲名) for (int i = LB_Playlist.Items.Count - 1; i >= 0; i--) { if (LB_Playlist.Items[i].ToString() == lstSongName[songId]) { LB_Playlist.Items.RemoveAt(i); break; } } UpdateUI(); }
2. 触发删除的时机
监听播放器的播放状态变化事件,当歌曲播放完成(状态变为停止且之前处于播放状态)时调用删除方法:
private void Player_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e) { // 判定为播放完成的状态:从播放转为停止 if (e.newState == 8 && Player.playState == WMPLib.WMPPlayState.wmppsStopped) { // currentPlayingSongId需在播放时提前保存 DeletePlayedSong(currentPlayingSongId); } }
二、现有代码规范评估与优化建议
1. Button_Add_Click方法问题与优化
存在的问题
- ID截取逻辑极不稳定:依赖固定字符串位置(
startIndex=2、length=3),一旦ListBox显示格式变化(如ID位数增减、前缀字符改变),会直接取错ID或报错。 - 数据库资源未正确释放:
MySqlCommand未用using管理,可能导致连接泄漏;AbrufLeser.Close()位置不合理,若之前未打开会引发异常。 - 耦合性过高:依赖全局集合
lstSongName、lstSongPfad,数据维护成本高,易出错。
优化后代码
建议绑定自定义实体到ListBox,避免字符串解析:
// 定义歌曲实体类 public class Song { public int ID { get; set; } public string Name { get; set; } public string Author { get; set; } public string Path { get; set; } // 自定义显示文本,兼顾用户可读性和数据完整性 public override string ToString() => $"[{ID}] {Name} - {Author}"; } // 优化后的添加按钮逻辑 private void Button_Add_Click(object sender, EventArgs e) { if (LB_Liste.SelectedItem is Song selectedSong) { using (MySqlCommand insertCmd = new MySqlCommand("INSERT INTO playlist (ID, Name, Path, Que) VALUES (@ID, @Name, @Path, @Que)", MyCon)) { insertCmd.Parameters.AddWithValue("@ID", selectedSong.ID); insertCmd.Parameters.AddWithValue("@Name", selectedSong.Name); insertCmd.Parameters.AddWithValue("@Path", selectedSong.Path); insertCmd.Parameters.AddWithValue("@Que", 0); insertCmd.ExecuteNonQuery(); } LB_Playlist.Items.Add(selectedSong.Name); UpdateUI(); } }
2. Button_Play_Click方法问题与优化
存在的问题
- 逻辑错误:
while循环遍历所有Playlist记录,但仅保留最后一条数据,实际应取排序后的第一条(待播放的第一首)。 - 资源管理缺失:
MySqlCommand、MySqlDataReader未用using自动释放,易导致连接池耗尽。 - 无异常处理:数据库查询失败时直接崩溃,无友好提示。
- 未保存播放ID:播放完成后无法准确定位要删除的歌曲。
优化后代码
private int currentPlayingSongId; // 保存当前播放歌曲的ID,供删除时使用 private void Button_Play_Click(object sender, EventArgs e) { try { // 只查询排序后的第一首待播放歌曲 using (MySqlCommand queryCmd = new MySqlCommand("SELECT ID, Name, Path FROM playlist ORDER BY que LIMIT 1", MyCon)) { using (MySqlDataReader reader = queryCmd.ExecuteReader()) { if (reader.Read()) { currentPlayingSongId = Convert.ToInt32(reader["ID"]); string playPath = reader["Path"].ToString(); Player.URL = playPath; TimerR.Start(); Timer_GIf.Start(); UpdateUI(); } else { MessageBox.Show("播放列表为空"); } } } } catch (MySqlException ex) { MessageBox.Show($"数据库查询失败:{ex.Message}"); } }
通用优化建议
- 封装数据库操作:将所有SQL操作(查询、增删)集中到单独的数据库工具类,避免UI层直接操作数据库,降低耦合。
- 使用ORM框架:推荐Dapper或Entity Framework Core,简化SQL编写,提升代码可读性和可维护性。
- 全局变量替换:避免直接使用全局的
MyCon、AbrufKommando等,改用局部变量+using管理,或封装到数据库类中。 - 完善异常处理:所有数据库操作添加
try-catch,捕获特定异常并给出用户友好提示。
内容的提问来源于stack exchange,提问作者ConflictMeow
相关产品推荐
相关产品推荐

